// Fill out your copyright notice in the Description page of Project Settings. #include "Widgets/BagConfigEditorWidget.h" #include "PropertyCustomizationHelpers.h" #include "Framework/Notifications/NotificationManager.h" #include "ProjectFish/DataAsset/ShapeAsset.h" #include "Widgets/BagConfigGridWidget.h" #include "Widgets/ShapeGridWidget.h" #include "Widgets/SkillListWidget.h" #include "Widgets/Notifications/SNotificationList.h" void SBagConfigEditorWidget::Construct(const FArguments& InArgs) { BagConfig = InArgs._BagConfigAsset; SelectedSkillAsset = nullptr; bIsPlacingSkill = false; SelectedSkillIndex = -1; ChildSlot [ SNew(SVerticalBox) // 背包选择器 + SVerticalBox::Slot() .AutoHeight() .Padding(5.0f) [ SNew(SHorizontalBox) + SHorizontalBox::Slot() .AutoWidth() .VAlign(VAlign_Center) .Padding(0, 0, 10, 0) [ SNew(STextBlock) .Text(FText::FromString(TEXT("背包形状:"))) .Font(FCoreStyle::GetDefaultFontStyle("Bold", 10)) ] + SHorizontalBox::Slot() .FillWidth(1.0f) [ SNew(SObjectPropertyEntryBox) .ObjectPath_Lambda([this]() { return BagConfig.IsValid() && BagConfig->BagShapeAsset ? BagConfig->BagShapeAsset->GetPathName() : FString(); }) .AllowedClass(UShapeAsset::StaticClass()) .OnObjectChanged(this, &SBagConfigEditorWidget::OnBagShapeAssetChanged) .DisplayUseSelected(true) .DisplayBrowse(true) .DisplayThumbnail(false) ] ] // 技能资源 选择器 + SVerticalBox::Slot() .AutoHeight() .Padding(5.0f) [ SNew(SHorizontalBox) + SHorizontalBox::Slot() .AutoWidth() .VAlign(VAlign_Center) .Padding(0, 0, 10, 0) [ SNew(STextBlock) .Text(FText::FromString(TEXT("选择要添加的技能:"))) .Font(FCoreStyle::GetDefaultFontStyle("Bold", 10)) ] + SHorizontalBox::Slot() .FillWidth(1.0f) [ SNew(SObjectPropertyEntryBox) .ObjectPath_Lambda([this]() { return SelectedSkillAsset.IsValid() ? SelectedSkillAsset->GetPathName() : FString(); }) .AllowedClass(USkillAsset::StaticClass()) .OnObjectChanged(this, &SBagConfigEditorWidget::OnSkillAssetChanged) .DisplayUseSelected(true) .DisplayBrowse(true) .DisplayThumbnail(false) ] ] // 技能按钮 + SVerticalBox::Slot() .AutoHeight() .Padding(5.0f) [ SNew(SHorizontalBox) + SHorizontalBox::Slot() .AutoWidth() .Padding(2.0f) [ SNew(SButton) .Text(FText::FromString(TEXT("添加当前选中的技能"))) .OnClicked(this, &SBagConfigEditorWidget::OnAddSkillClicked) .IsEnabled_Lambda([this]() { return BagConfig.IsValid() && BagConfig->BagShapeAsset != nullptr && SelectedSkillAsset.IsValid(); }) ] + SHorizontalBox::Slot() .AutoWidth() .Padding(2.0f) [ SNew(SButton) .Text(FText::FromString(TEXT("移除当前选中的技能"))) .OnClicked(this, &SBagConfigEditorWidget::OnRemoveSkillClicked) .IsEnabled_Lambda([this]() { return SelectedSkillAsset.IsValid(); }) ] + SHorizontalBox::Slot() .AutoWidth() .Padding(2.0f) [ SNew(SButton) .Text(FText::FromString(TEXT("移除所有技能"))) .OnClicked(this, &SBagConfigEditorWidget::OnClearAllSkillsClicked) .IsEnabled_Lambda([this]() { return BagConfig.IsValid() && BagConfig->GetSkillCount() > 0; }) ] ] // 主编辑区域 + SVerticalBox::Slot() .FillHeight(1.0f) [ SNew(SSplitter) .Orientation(Orient_Horizontal) // 左侧:背包格子视图 + SSplitter::Slot() .Value(0.7f) [ SNew(SBox) .HAlign(HAlign_Center) .VAlign(VAlign_Center) .Padding(10.0f) [ SNew(SVerticalBox) + SVerticalBox::Slot() .AutoHeight() .HAlign(HAlign_Center) .Padding(0, 0, 0, 10) [ SNew(STextBlock) .Text_Lambda([this]() { if (!BagConfig.IsValid()) { return FText::FromString(TEXT("No Bag Class")); } else if (!BagConfig->BagShapeAsset) { return FText::FromString(TEXT("Please select a Bag Shape Asset above")); } else { return FText::FromString(FString::Printf(TEXT("Bag: %s (%dx%d)"), *BagConfig->BagShapeAsset->GetName(), BagConfig->BagShapeAsset->ShapeWidth, BagConfig->BagShapeAsset->ShapeHeight)); } }) .Font(FCoreStyle::GetDefaultFontStyle("Bold", 12)) .ColorAndOpacity_Lambda([this]() { return (!BagConfig.IsValid() || !BagConfig->BagShapeAsset) ? FSlateColor(FLinearColor::Red) : FSlateColor(FLinearColor::White); }) ] + SVerticalBox::Slot() .AutoHeight() .HAlign(HAlign_Center) [ SAssignNew(BagGridWidget, SBagConfigGridWidget) .BagConfig(BagConfig.Get()) .OnGridCellClicked(this, &SBagConfigEditorWidget::OnGridCellClicked) .Visibility_Lambda([this]() { return (BagConfig.IsValid() && BagConfig->BagShapeAsset) ? EVisibility::Visible : EVisibility::Hidden; }) ] ] ] // 右侧:技能列表 + SSplitter::Slot() .Value(0.3f) [ SNew(SVerticalBox) + SVerticalBox::Slot() .AutoHeight() .Padding(5.0f) [ SNew(STextBlock) .Text(FText::FromString(TEXT("已添加技能:"))) .Font(FCoreStyle::GetDefaultFontStyle("Bold", 12)) ] + SVerticalBox::Slot() .FillHeight(1.0f) .Padding(5.0f) [ SAssignNew(SkillListWidget, SSkillListWidget) .BagConfig(BagConfig.Get()) .OnSkillSelected(this, &SBagConfigEditorWidget::OnSkillSelected) ] ] ] ]; RefreshUI(); } FReply SBagConfigEditorWidget::OnAddSkillClicked() { if (!BagConfig.IsValid() || !BagConfig->BagShapeAsset || !SelectedSkillAsset.IsValid()) { ShowWarningMessage(TEXT("Please select a bag shape asset and a skill object first!")); return FReply::Handled(); } // 进入放置模式 bIsPlacingSkill = true; ShowWarningMessage(TEXT("Click on the grid to place the skill")); return FReply::Handled(); } FReply SBagConfigEditorWidget::OnRemoveSkillClicked() { if (!BagConfig.IsValid() || SelectedSkillIndex < 0) { return FReply::Handled(); } if (BagConfig->RemoveSkill(SelectedSkillIndex)) { SelectedSkillIndex = -1; RefreshUI(); // 标记资源为已修改 BagConfig->MarkPackageDirty(); } return FReply::Handled(); } FReply SBagConfigEditorWidget::OnClearAllSkillsClicked() { if (!BagConfig.IsValid()) { return FReply::Handled(); } BagConfig->ClearAllSkills(); SelectedSkillIndex = -1; RefreshUI(); // 标记资源为已修改 BagConfig->MarkPackageDirty(); return FReply::Handled(); } void SBagConfigEditorWidget::OnBagShapeAssetChanged(const FAssetData& AssetData) { if (!BagConfig.IsValid()) { return; } // 获取新选择的BagShapeAsset UShapeAsset* NewBagShapeAsset = Cast(AssetData.GetAsset()); // 如果选择了不同的资源,清空现有技能并更新引用 if (BagConfig->BagShapeAsset != NewBagShapeAsset) { // 清空现有技能(因为新的背包形状可能不兼容) if (NewBagShapeAsset && BagConfig->GetSkillCount() > 0) { BagConfig->ClearAllSkills(); ShowWarningMessage(TEXT("Existing skills cleared due to bag shape change")); } // 更新BagShapeAsset引用 BagConfig->BagShapeAsset = NewBagShapeAsset; // 标记资源为已修改 BagConfig->MarkPackageDirty(); // 刷新UI RefreshUI(); if (NewBagShapeAsset) { ShowWarningMessage(FString::Printf(TEXT("Bag shape set to: %s"), *NewBagShapeAsset->GetName())); } else { ShowWarningMessage(TEXT("Bag shape asset cleared")); } } } void SBagConfigEditorWidget::OnSkillAssetChanged(const FAssetData& AssetData) { SelectedSkillAsset = Cast(AssetData.GetAsset()); } void SBagConfigEditorWidget::OnSkillSelected(int32 SkillIndex) { SelectedSkillIndex = SkillIndex; } void SBagConfigEditorWidget::OnGridCellClicked(int32 X, int32 Y) { if (!BagConfig.IsValid()) { return; } if (bIsPlacingSkill && SelectedSkillAsset.IsValid()) { // 尝试在指定位置放置技能 if (BagConfig->CanPlaceSkill(SelectedSkillAsset.Get(), X, Y)) { if (BagConfig->AddSkill(SelectedSkillAsset.Get(), X, Y)) { BagConfig->MarkPackageDirty(); RefreshUI(); ShowWarningMessage(FString::Printf(TEXT("Successfully placed skill '%s' at (%d,%d)"), *SelectedSkillAsset->SkillName.ToString(), X, Y)); // 退出放置模式 bIsPlacingSkill = false; } else { ShowWarningMessage(TEXT("Failed to place skill!")); } } else { ShowWarningMessage(TEXT("Cannot place skill at this position!")); } } else { // // 选择现有技能 // int32 SkillIndex = BagConfig->GetSkillAtPosition(X, Y); // SelectedSkillIndex = SkillIndex; // // if (SkillListWidget.IsValid()) // { // SkillListWidget->SetSelectedSkill(SkillIndex); // } } } void SBagConfigEditorWidget::RefreshUI() { if (BagGridWidget.IsValid()) { BagGridWidget->RefreshGrid(); } if (SkillListWidget.IsValid()) { SkillListWidget->RefreshSkillList(); } } void SBagConfigEditorWidget::ShowWarningMessage(const FString& Message) { FNotificationInfo Info(FText::FromString(Message)); Info.bFireAndForget = true; Info.FadeOutDuration = 3.0f; Info.ExpireDuration = 3.0f; FSlateNotificationManager::Get().AddNotification(Info); }