diff --git a/ProjectFish/Source/ProjectFishEditor/Private/Widgets/BagShapeEditorWidget.cpp b/ProjectFish/Source/ProjectFishEditor/Private/Widgets/BagShapeEditorWidget.cpp index 2cd00ab..9baba92 100644 --- a/ProjectFish/Source/ProjectFishEditor/Private/Widgets/BagShapeEditorWidget.cpp +++ b/ProjectFish/Source/ProjectFishEditor/Private/Widgets/BagShapeEditorWidget.cpp @@ -2,9 +2,238 @@ #include "Widgets/BagShapeEditorWidget.h" +#include "Widgets/Input/SSpinBox.h" +#include "EditorStyleSet.h" void SBagShapeEditorWidget::Construct(const FArguments& InArgs) { BagShapeAsset = InArgs._BagShapeAsset; + + ChildSlot + [ + SNew(SSplitter) + .Orientation(Orient_Vertical) + + SSplitter::Slot() + .Value(0.2f) + [ + CreateSizeControls() + ] + + SSplitter::Slot() + .Value(0.1f) + [ + CreateGridControls() + ] + + SSplitter::Slot() + .Value(0.7f) + [ + SNew(SScrollBox) + + SScrollBox::Slot() + [ + SNew(SBorder) + .BorderImage(FEditorStyle::GetBrush("ToolPanel.GroupBorder")) + .Padding(10.0f) + [ + SNew(SBox) + .HAlign(HAlign_Center) + .VAlign(VAlign_Center) + [ + SAssignNew(GridWidget, SBagShapeGridWidget) + .BagShapeAsset(BagShapeAsset.Get()) + .OnSlotClicked(this, &SBagShapeEditorWidget::OnSlotClicked) + ] + ] + ] + ] + ]; +} + +void SBagShapeEditorWidget::RefreshGrid() +{ + if (GridWidget.IsValid()) + { + GridWidget->UpdateBagShapeAsset(BagShapeAsset.Get()); + } +} + +TSharedRef SBagShapeEditorWidget::CreateSizeControls() +{ + return SNew(SBorder) + .BorderImage(FEditorStyle::GetBrush("ToolPanel.GroupBorder")) + .Padding(10.0f) + [ + SNew(SVerticalBox) + + SVerticalBox::Slot() + .AutoHeight() + .Padding(0, 5) + [ + SNew(STextBlock) + .Text(FText::FromString("Bag Size Settings")) + .Font(FCoreStyle::GetDefaultFontStyle("Bold", 14)) + ] + + SVerticalBox::Slot() + .AutoHeight() + .Padding(0, 5) + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .AutoWidth() + .VAlign(VAlign_Center) + .Padding(0, 0, 10, 0) + [ + SNew(STextBlock) + .Text(FText::FromString("Width:")) + ] + + SHorizontalBox::Slot() + .AutoWidth() + [ + SNew(SBox) + .WidthOverride(100.0f) + [ + SNew(SSpinBox) + .MinValue(1) + .MaxValue(10) + .Value(this, &SBagShapeEditorWidget::GetBagWidth) + .OnValueChanged(this, &SBagShapeEditorWidget::OnWidthChanged) + ] + ] + + SHorizontalBox::Slot() + .AutoWidth() + .VAlign(VAlign_Center) + .Padding(20, 0, 10, 0) + [ + SNew(STextBlock) + .Text(FText::FromString("Width:")) + ] + + SHorizontalBox::Slot() + .AutoWidth() + [ + SNew(SBox) + .WidthOverride(100.0f) + [ + SNew(SSpinBox) + .MinValue(1) + .MaxValue(10) + .Value(this, &SBagShapeEditorWidget::GetBagHeight) + .OnValueChanged(this, &SBagShapeEditorWidget::OnHeightChanged) + ] + ] + ] + ]; +} + +int32 SBagShapeEditorWidget::GetBagWidth() const +{ + return BagShapeAsset.IsValid() ? BagShapeAsset->BagWidth : 5; +} + +int32 SBagShapeEditorWidget::GetBagHeight() const +{ + return BagShapeAsset.IsValid() ? BagShapeAsset->BagHeight : 5; +} + +void SBagShapeEditorWidget::OnWidthChanged(int32 NewWidth) +{ + if (BagShapeAsset.IsValid() && NewWidth != BagShapeAsset->BagWidth) + { + BagShapeAsset->BagWidth = NewWidth; + BagShapeAsset->InitializeBagShape(); + BagShapeAsset->MarkPackageDirty(); + RefreshGrid(); + } +} + +void SBagShapeEditorWidget::OnHeightChanged(int32 NewHeight) +{ + if (BagShapeAsset.IsValid() && NewHeight != BagShapeAsset->BagHeight) + { + BagShapeAsset->BagHeight = NewHeight; + BagShapeAsset->InitializeBagShape(); + BagShapeAsset->MarkPackageDirty(); + RefreshGrid(); + } +} + +TSharedRef SBagShapeEditorWidget::CreateGridControls() +{ + return SNew(SBorder) + .BorderImage(FEditorStyle::GetBrush("ToolPanel.GroupBorder")) + .Padding(10.0f) + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .AutoWidth() + .Padding(0, 0, 10, 0) + [ + SNew(SButton) + .Text(FText::FromString("All Enable")) + .OnClicked(this, &SBagShapeEditorWidget::OnAllEnableClicked) + ] + + SHorizontalBox::Slot() + .AutoWidth() + .Padding(0, 0, 10, 0) + [ + SNew(SButton) + .Text(FText::FromString("All Disable")) + .OnClicked(this, &SBagShapeEditorWidget::OnAllDisableClicked) + ] + + ]; +} + +FReply SBagShapeEditorWidget::OnAllEnableClicked() +{ + if (BagShapeAsset.IsValid()) + { + BagShapeAsset->InitializeBagShape(); + BagShapeAsset->MarkPackageDirty(); + RefreshGrid(); + RefreshThumbnail(); + } + return FReply::Handled(); +} + +FReply SBagShapeEditorWidget::OnAllDisableClicked() +{ + if (BagShapeAsset.IsValid()) + { + for (int32 X = 0; X < BagShapeAsset->BagWidth; X++) + { + for (int32 Y = 0; Y < BagShapeAsset->BagHeight; Y++) + { + BagShapeAsset->SetSlotActive(X, Y, false); + } + } + BagShapeAsset->MarkPackageDirty(); + RefreshGrid(); + RefreshThumbnail(); + } + return FReply::Handled(); +} + +void SBagShapeEditorWidget::OnSlotClicked(int32 X, int32 Y) +{ + if (!BagShapeAsset.IsValid()) + { + return; + } + + bool bCurrentState = BagShapeAsset->IsSlotActive(X, Y); + BagShapeAsset->SetSlotActive(X, Y, !bCurrentState); + + // Refresh the grid widget + if (GridWidget.IsValid()) + { + GridWidget->UpdateBagShapeAsset(BagShapeAsset.Get()); + } + + // Mark the asset as modified + BagShapeAsset->MarkPackageDirty(); + + // 强制刷新缩略图 + RefreshThumbnail(); +} + +void SBagShapeEditorWidget::RefreshThumbnail() +{ } diff --git a/ProjectFish/Source/ProjectFishEditor/Private/Widgets/BagShapeGridWidget.cpp b/ProjectFish/Source/ProjectFishEditor/Private/Widgets/BagShapeGridWidget.cpp new file mode 100644 index 0000000..1efe50b --- /dev/null +++ b/ProjectFish/Source/ProjectFishEditor/Private/Widgets/BagShapeGridWidget.cpp @@ -0,0 +1,177 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "Widgets/BagShapeGridWidget.h" + +const float SBagShapeGridWidget::CellSize = 32.0f; +const float SBagShapeGridWidget::SeparatorWidth = 2.0f; +void SBagShapeGridWidget::Construct(const FArguments& InArgs) +{ + BagShapeAsset = InArgs._BagShapeAsset; + OnSlotClicked = InArgs._OnSlotClicked; +} + +void SBagShapeGridWidget::UpdateBagShapeAsset(UBagShapeAsset* InBagShapeAsset) +{ + BagShapeAsset = InBagShapeAsset; + Invalidate(EInvalidateWidget::Paint); +} + +FReply SBagShapeGridWidget::OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) +{ + if (MouseEvent.GetEffectingButton() == EKeys::LeftMouseButton && BagShapeAsset.IsValid()) + { + FVector2D LocalPosition = MyGeometry.AbsoluteToLocal(MouseEvent.GetScreenSpacePosition()); + FVector2D GridCell = GetGridCellFromPosition(LocalPosition); + + int32 GridX = FMath::FloorToInt(GridCell.X); + int32 GridY = FMath::FloorToInt(GridCell.Y); + + if (IsValidGridPosition(GridX, GridY)) + { + OnSlotClicked.ExecuteIfBound(GridX, GridY); + return FReply::Handled(); + } + } + + return FReply::Unhandled(); +} + +int32 SBagShapeGridWidget::OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, + const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, + const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const +{ + if (!BagShapeAsset.IsValid()) + { + return LayerId; + } + + // Calculate grid dimensions with separators + float Scale = CellSize + SeparatorWidth; + float GridWidth = BagShapeAsset->BagWidth * Scale - SeparatorWidth; + float GridHeight = BagShapeAsset->BagHeight * Scale - SeparatorWidth; + + // Center the grid in the available space + FVector2D GridStartPos = FVector2D( + (AllottedGeometry.GetLocalSize().X - GridWidth) * 0.5f, + (AllottedGeometry.GetLocalSize().Y - GridHeight) * 0.5f + ); + + // Draw background + FSlateDrawElement::MakeBox( + OutDrawElements, + LayerId, + AllottedGeometry.ToPaintGeometry(AllottedGeometry.GetLocalSize(), FSlateLayoutTransform()), + FCoreStyle::Get().GetBrush("WhiteBrush"), + ESlateDrawEffect::None, + FLinearColor(0.1f, 0.1f, 0.1f, 1.0f) + ); + + // Draw cells + for (int32 Y = 0; Y < BagShapeAsset->BagHeight; Y++) + { + for (int32 X = 0; X < BagShapeAsset->BagWidth; X++) + { + FVector2D CellPos = GridStartPos + FVector2D(X * Scale, Y * Scale); + bool bIsActive = BagShapeAsset->IsSlotActive(X, Y); + + // Draw cell background + FLinearColor CellColor = bIsActive ? FLinearColor(0.2f, 0.8f, 0.2f, 1.0f) : FLinearColor(0.15f, 0.15f, 0.15f, 1.0f); + FSlateDrawElement::MakeBox( + OutDrawElements, + LayerId + 1, + AllottedGeometry.ToPaintGeometry(FVector2D(CellSize, CellSize), FSlateLayoutTransform(CellPos)), + FCoreStyle::Get().GetBrush("WhiteBrush"), + ESlateDrawEffect::None, + CellColor + ); + } + } + + // Draw vertical separators + for (int32 X = 1; X < BagShapeAsset->BagWidth; X++) + { + float SeparatorX = GridStartPos.X + X * Scale - SeparatorWidth; + FSlateDrawElement::MakeBox( + OutDrawElements, + LayerId + 2, + AllottedGeometry.ToPaintGeometry(FVector2D(SeparatorWidth, GridHeight), FSlateLayoutTransform(FVector2D(SeparatorX, GridStartPos.Y))), + FCoreStyle::Get().GetBrush("WhiteBrush"), + ESlateDrawEffect::None, + FLinearColor::White + ); + } + + // Draw horizontal separators + for (int32 Y = 1; Y < BagShapeAsset->BagHeight; Y++) + { + float SeparatorY = GridStartPos.Y + Y * Scale - SeparatorWidth; + FSlateDrawElement::MakeBox( + OutDrawElements, + LayerId + 2, + AllottedGeometry.ToPaintGeometry(FVector2D(GridWidth, SeparatorWidth), FSlateLayoutTransform(FVector2D(GridStartPos.X, SeparatorY))), + FCoreStyle::Get().GetBrush("WhiteBrush"), + ESlateDrawEffect::None, + FLinearColor::White + ); + } + + // Draw outer border + FSlateDrawElement::MakeBox( + OutDrawElements, + LayerId + 3, + AllottedGeometry.ToPaintGeometry(FVector2D(GridWidth, GridHeight), FSlateLayoutTransform(GridStartPos)), + FCoreStyle::Get().GetBrush("Border"), + ESlateDrawEffect::None, + FLinearColor::White + ); + + return LayerId + 4; +} + +FVector2D SBagShapeGridWidget::ComputeDesiredSize(float X) const +{ + if (!BagShapeAsset.IsValid()) + { + return FVector2D(200, 200); + } + + float Scale = CellSize + SeparatorWidth; + return FVector2D( + BagShapeAsset->BagWidth * Scale - SeparatorWidth + 20.0f, // Add padding + BagShapeAsset->BagHeight * Scale - SeparatorWidth + 20.0f + ); +} + +FVector2D SBagShapeGridWidget::GetGridCellFromPosition(const FVector2D& Position) const +{ + if (!BagShapeAsset.IsValid()) + { + return FVector2D(-1, -1); + } + + float Scale = CellSize + SeparatorWidth; + float GridWidth = BagShapeAsset->BagWidth * Scale - SeparatorWidth; + float GridHeight = BagShapeAsset->BagHeight * Scale - SeparatorWidth; + + FVector2D GridStartPos = FVector2D( + (GetCachedGeometry().GetLocalSize().X - GridWidth) * 0.5f, + (GetCachedGeometry().GetLocalSize().Y - GridHeight) * 0.5f + ); + + FVector2D RelativePos = Position - GridStartPos; + + return FVector2D( + RelativePos.X / Scale, + RelativePos.Y / Scale + ); +} + +bool SBagShapeGridWidget::IsValidGridPosition(int32 X, int32 Y) const +{ + if (!BagShapeAsset.IsValid()) + { + return false; + } + return X >= 0 && X < BagShapeAsset->BagWidth && Y >= 0 && Y < BagShapeAsset->BagHeight; +} diff --git a/ProjectFish/Source/ProjectFishEditor/ProjectFishEditor.Build.cs b/ProjectFish/Source/ProjectFishEditor/ProjectFishEditor.Build.cs index 7da2baa..e8f38a1 100644 --- a/ProjectFish/Source/ProjectFishEditor/ProjectFishEditor.Build.cs +++ b/ProjectFish/Source/ProjectFishEditor/ProjectFishEditor.Build.cs @@ -23,7 +23,8 @@ public class ProjectFishEditor : ModuleRules "ProjectFish", "InputCore", "AssetTools", - "UnrealEd" + "UnrealEd", + "EditorStyle" } ); } diff --git a/ProjectFish/Source/ProjectFishEditor/Public/Widgets/BagShapeEditorWidget.h b/ProjectFish/Source/ProjectFishEditor/Public/Widgets/BagShapeEditorWidget.h index 934dafc..7aec4fe 100644 --- a/ProjectFish/Source/ProjectFishEditor/Public/Widgets/BagShapeEditorWidget.h +++ b/ProjectFish/Source/ProjectFishEditor/Public/Widgets/BagShapeEditorWidget.h @@ -3,6 +3,7 @@ #pragma once #include "CoreMinimal.h" +#include "BagShapeGridWidget.h" #include "ProjectFish/DataAsset/BagShapeAsset.h" /** @@ -16,6 +17,32 @@ public: SLATE_END_ARGS() void Construct(const FArguments& InArgs); +private: + /** Refresh the grid display */ + void RefreshGrid(); + + //背包大小UI + TSharedRef CreateSizeControls(); + /** Get the current bag width */ + int32 GetBagWidth() const; + /** Get the current bag height */ + int32 GetBagHeight() const; + /** Handle width spin box value change */ + void OnWidthChanged(int32 NewWidth); + /** Handle height spin box value change */ + void OnHeightChanged(int32 NewHeight); + + + //重置背包状态 + TSharedRef CreateGridControls(); + FReply OnAllEnableClicked(); + FReply OnAllDisableClicked(); + + //点击背包格子 + void OnSlotClicked(int32 X, int32 Y); + //刷新图标 + void RefreshThumbnail(); private: TWeakObjectPtr BagShapeAsset; + TSharedPtr GridWidget; }; diff --git a/ProjectFish/Source/ProjectFishEditor/Public/Widgets/BagShapeGridWidget.h b/ProjectFish/Source/ProjectFishEditor/Public/Widgets/BagShapeGridWidget.h new file mode 100644 index 0000000..95e6ee6 --- /dev/null +++ b/ProjectFish/Source/ProjectFishEditor/Public/Widgets/BagShapeGridWidget.h @@ -0,0 +1,39 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "ProjectFish/DataAsset/BagShapeAsset.h" + +DECLARE_DELEGATE_TwoParams(FOnSlotClicked, int32, int32); +/** + * + */ +class SBagShapeGridWidget : public SCompoundWidget +{ +public: + SLATE_BEGIN_ARGS(SBagShapeGridWidget) {} + SLATE_ARGUMENT(UBagShapeAsset*, BagShapeAsset) + SLATE_EVENT(FOnSlotClicked, OnSlotClicked) +SLATE_END_ARGS() + + void Construct(const FArguments& InArgs); + + void UpdateBagShapeAsset(UBagShapeAsset* InBagShapeAsset); + + // SWidget interface + virtual FReply OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override; + virtual int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, + FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override; + virtual FVector2D ComputeDesiredSize(float) const override; + +private: + static const float CellSize; + static const float SeparatorWidth; + + TWeakObjectPtr BagShapeAsset; + FOnSlotClicked OnSlotClicked; + + FVector2D GetGridCellFromPosition(const FVector2D& Position) const; + bool IsValidGridPosition(int32 X, int32 Y) const; +};