Files
UnrealEngine/Engine/Source/Editor/LandscapeEditor/Private/LandscapeSplineDetails.cpp
2025-05-18 13:04:45 +08:00

407 lines
16 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "LandscapeSplineDetails.h"
#include "LandscapeSplineSelection.h"
#include "Widgets/DeclarativeSyntaxSupport.h"
#include "Widgets/SBoxPanel.h"
#include "LandscapeEdMode.h"
#include "Widgets/Text/STextBlock.h"
#include "Widgets/Input/SButton.h"
#include "Widgets/Layout/SSeparator.h"
#include "Widgets/Input/SButton.h"
#include "EditorModeManager.h"
#include "EditorModes.h"
#include "DetailWidgetRow.h"
#include "DetailCategoryBuilder.h"
#include "DetailLayoutBuilder.h"
#include "ILandscapeSplineInterface.h"
#define LOCTEXT_NAMESPACE "LandscapeSplineDetails"
TSharedRef<IDetailCustomization> FLandscapeSplineDetails::MakeInstance()
{
return MakeShareable(new FLandscapeSplineDetails);
}
void FLandscapeSplineDetails::CustomizeDetails(IDetailLayoutBuilder& DetailBuilder)
{
IDetailCategoryBuilder& LandscapeSplineCategory = DetailBuilder.EditCategory("LandscapeSpline", FText::GetEmpty(), ECategoryPriority::Transform);
LandscapeSplineCategory.AddCustomRow(FText::GetEmpty())
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.Padding(0, 0, 2, 0)
.VAlign(VAlign_Center)
.FillWidth(1)
[
SNew(STextBlock)
.Text_Raw(this, &FLandscapeSplineDetails::OnGetSplineOwningLandscapeText)
]
];
FMargin ButtonPadding(2.f, 0.f);
LandscapeSplineCategory.AddCustomRow(LOCTEXT("SelectSplineElements", "Select Spline Elements"))
.RowTag("SelectSplineElements")
.NameContent()
[
SNew(STextBlock)
.Font(IDetailLayoutBuilder::GetDetailFont())
.Text(IsSegmentSelectModeEnabled() ? LOCTEXT("SelectSplineSegments", "Select Spline Segments") : LOCTEXT("SelectSplineControlPoints", "Select Spline Points"))
]
.ValueContent()
.VAlign(VAlign_Fill)
.MaxDesiredWidth(170.f)
.MinDesiredWidth(170.f)
[
SNew(SHorizontalBox)
.Clipping(EWidgetClipping::ClipToBounds)
+ SHorizontalBox::Slot()
.VAlign(VAlign_Center)
.AutoWidth()
.Padding(ButtonPadding)
[
SNew(SButton)
.ButtonStyle(FAppStyle::Get(), "SplineComponentDetails.SelectFirst")
.ContentPadding(2.0f)
.ToolTipText(IsSegmentSelectModeEnabled() ? LOCTEXT("SelectFirstSplineSegmentToolTip", "Select first spline segment.") : LOCTEXT("SelectFirstSplinePointToolTip", "Select first spline point."))
.OnClicked(this, &FLandscapeSplineDetails::OnSelectEndLinearSplineElementButtonClicked, ESplineNavigationFlags::DirectionBackward)
.IsEnabled(this, &FLandscapeSplineDetails::HasEndLinearSplineElement, ESplineNavigationFlags::DirectionBackward)
]
+ SHorizontalBox::Slot()
.AutoWidth()
.VAlign(VAlign_Center)
.Padding(ButtonPadding)
[
SNew(SButton)
.ButtonStyle(FAppStyle::Get(), "SplineComponentDetails.AddPrev")
.ContentPadding(2.f)
.VAlign(VAlign_Center)
.HAlign(HAlign_Center)
.ToolTipText(IsSegmentSelectModeEnabled() ? LOCTEXT("SelectAddPrevSplineSegmentToolTip", "Add previous segment to current selection.") : LOCTEXT("SelectAddPrevSplinePointToolTip", "Add previous point to current selection."))
.OnClicked(this, &FLandscapeSplineDetails::OnSelectAdjacentLinearSplineElementButtonClicked, (ESplineNavigationFlags::DirectionBackward | ESplineNavigationFlags::AddToSelection))
.IsEnabled(this, &FLandscapeSplineDetails::HasAdjacentLinearSplineElement, (ESplineNavigationFlags::DirectionBackward | ESplineNavigationFlags::AddToSelection))
]
+ SHorizontalBox::Slot()
.VAlign(VAlign_Center)
.AutoWidth()
[
SNew(SButton)
.ButtonStyle(FAppStyle::Get(), "SplineComponentDetails.SelectPrev")
.ContentPadding(2.f)
.VAlign(VAlign_Center)
.HAlign(HAlign_Center)
.ToolTipText(IsSegmentSelectModeEnabled() ? LOCTEXT("SelectPrevSplineSegmentToolTip", "Select previous segment.") : LOCTEXT("SelectPrevPointToolTip", "Select previous point."))
.OnClicked(this, &FLandscapeSplineDetails::OnSelectAdjacentLinearSplineElementButtonClicked, ESplineNavigationFlags::DirectionBackward)
.IsEnabled(this, &FLandscapeSplineDetails::HasAdjacentLinearSplineElement, ESplineNavigationFlags::DirectionBackward)
]
+ SHorizontalBox::Slot()
.VAlign(VAlign_Center)
.AutoWidth()
.Padding(ButtonPadding)
[
SNew(SButton)
.ButtonStyle(FAppStyle::Get(), "SplineComponentDetails.SelectAll")
.ContentPadding(2.f)
.VAlign(VAlign_Center)
.HAlign(HAlign_Center)
.ToolTipText(IsSegmentSelectModeEnabled() ? LOCTEXT("SelectAllSplineSegmentToolTip", "Select all segments.") : LOCTEXT("SelectAllSplinePointsToolTip", "Select all points."))
.OnClicked(this, &FLandscapeSplineDetails::OnSelectAllConnectedSplineElementsButtonClicked)
]
+ SHorizontalBox::Slot()
.AutoWidth()
.VAlign(VAlign_Center)
.Padding(ButtonPadding)
[
SNew(SButton)
.ButtonStyle(FAppStyle::Get(), "SplineComponentDetails.SelectNext")
.ContentPadding(2.f)
.VAlign(VAlign_Center)
.HAlign(HAlign_Center)
.ToolTipText(IsSegmentSelectModeEnabled() ? LOCTEXT("SelectNextSplineSegmentToolTip", "Select next segment.") : LOCTEXT("SelectNextSplinePointToolTip", "Select next point."))
.OnClicked(this, &FLandscapeSplineDetails::OnSelectAdjacentLinearSplineElementButtonClicked, ESplineNavigationFlags::DirectionForward)
.IsEnabled(this, &FLandscapeSplineDetails::HasAdjacentLinearSplineElement, ESplineNavigationFlags::DirectionForward)
]
+ SHorizontalBox::Slot()
.AutoWidth()
.VAlign(VAlign_Center)
.Padding(ButtonPadding)
[
SNew(SButton)
.ButtonStyle(FAppStyle::Get(), "SplineComponentDetails.AddNext")
.ContentPadding(2.f)
.VAlign(VAlign_Center)
.HAlign(HAlign_Center)
.ToolTipText(IsSegmentSelectModeEnabled() ? LOCTEXT("SelectAddNextSplineSegmentToolTip", "Add next segment to current selection.") : LOCTEXT("SelectAddNextSplinePointToolTip", "Add next point to current selection."))
.OnClicked(this, &FLandscapeSplineDetails::OnSelectAdjacentLinearSplineElementButtonClicked, (ESplineNavigationFlags::DirectionForward | ESplineNavigationFlags::AddToSelection))
.IsEnabled(this, &FLandscapeSplineDetails::HasAdjacentLinearSplineElement, (ESplineNavigationFlags::DirectionForward | ESplineNavigationFlags::AddToSelection))
]
+ SHorizontalBox::Slot()
.VAlign(VAlign_Center)
.AutoWidth()
.Padding(ButtonPadding)
[
SNew(SButton)
.ButtonStyle(FAppStyle::Get(), "SplineComponentDetails.SelectLast")
.ContentPadding(2.0f)
.VAlign(VAlign_Center)
.HAlign(HAlign_Center)
.ToolTipText(IsSegmentSelectModeEnabled() ? LOCTEXT("SelectLastSplineSegmentToolTip", "Select last spline segment.") : LOCTEXT("SelectLastSplinePointToolTip", "Select last spline point."))
.OnClicked(this, &FLandscapeSplineDetails::OnSelectEndLinearSplineElementButtonClicked, ESplineNavigationFlags::DirectionForward)
.IsEnabled(this, &FLandscapeSplineDetails::HasEndLinearSplineElement, ESplineNavigationFlags::DirectionForward)
]
// Add a vertical divider to separate navigation with conversion
+ SHorizontalBox::Slot()
.VAlign(VAlign_Center)
.AutoWidth()
.Padding(ButtonPadding * 3)
[
SNew(SSeparator)
.Orientation(EOrientation::Orient_Vertical)
.Thickness(2.f)
]
+ SHorizontalBox::Slot()
.VAlign(VAlign_Center)
.AutoWidth()
[
SNew(SButton)
.ButtonStyle(FAppStyle::Get(), IsSegmentSelectModeEnabled() ? "SplineComponentDetails.ConvertToPoints" : "SplineComponentDetails.ConvertToSegments")
.ContentPadding(ButtonPadding)
.VAlign(VAlign_Center)
.HAlign(HAlign_Center)
.ToolTipText(IsSegmentSelectModeEnabled() ? LOCTEXT("SelectConvertSplineSegmentsToPoints", "Switch selected segments to points.") : LOCTEXT("SelectConvertSplinePointsToSegments", "Switch selected points to segments."))
.OnClicked(this, &FLandscapeSplineDetails::OnToggleSplineSelectionTypeButtonClicked)
]
];
LandscapeSplineCategory.AddCustomRow(FText::GetEmpty())
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.VAlign(VAlign_Center)
.FillWidth(1)
[
SNew(SButton)
.Text(LOCTEXT("Move Selected ControlPnts+Segs to Current level", "Move to current level"))
.HAlign(HAlign_Center)
.OnClicked(this, &FLandscapeSplineDetails::OnMoveToCurrentLevelButtonClicked)
.IsEnabled(this, &FLandscapeSplineDetails::IsMoveToCurrentLevelButtonEnabled)
]
];
LandscapeSplineCategory.AddCustomRow(FText::GetEmpty())
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.VAlign(VAlign_Center)
.FillWidth(1)
[
SNew(SButton)
.Text(LOCTEXT("Move Spline Mesh Components to Proper level", "Update Spline Mesh Levels"))
.HAlign(HAlign_Center)
.OnClicked(this, &FLandscapeSplineDetails::OnUpdateSplineMeshLevelsButtonClicked)
.IsEnabled(this, &FLandscapeSplineDetails::IsUpdateSplineMeshLevelsButtonEnabled)
]
];
IDetailCategoryBuilder& LandscapeSplineSegmentCategory = DetailBuilder.EditCategory("LandscapeSplineSegment", FText::GetEmpty(), ECategoryPriority::Default);
LandscapeSplineSegmentCategory.AddCustomRow(FText::GetEmpty())
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.Padding(0, 0, 2, 0)
.VAlign(VAlign_Center)
.FillWidth(1)
[
SNew(SButton)
.Text(LOCTEXT("FlipSegment", "Flip Selected Segment(s)"))
.HAlign(HAlign_Center)
.OnClicked(this, &FLandscapeSplineDetails::OnFlipSegmentButtonClicked)
.IsEnabled(this, &FLandscapeSplineDetails::IsFlipSegmentButtonEnabled)
]
];
}
class FEdModeLandscape* FLandscapeSplineDetails::GetEditorMode() const
{
return (FEdModeLandscape*)GLevelEditorModeTools().GetActiveMode(FBuiltinEditorModes::EM_Landscape);
}
bool FLandscapeSplineDetails::IsSegmentSelectModeEnabled() const
{
FEdModeLandscape* LandscapeEdMode = GetEditorMode();
if (LandscapeEdMode && LandscapeEdMode->CurrentToolTarget.LandscapeInfo.IsValid() && LandscapeEdMode->CurrentToolTarget.LandscapeInfo->GetCurrentLevelLandscapeProxy(true))
{
return LandscapeEdMode->HasSelectedSplineSegments();
}
return false;
}
FReply FLandscapeSplineDetails::OnFlipSegmentButtonClicked()
{
FEdModeLandscape* LandscapeEdMode = GetEditorMode();
if (LandscapeEdMode && LandscapeEdMode->CurrentToolTarget.LandscapeInfo.IsValid() && LandscapeEdMode->CurrentToolTarget.LandscapeInfo->GetCurrentLevelLandscapeProxy(true))
{
LandscapeEdMode->FlipSelectedSplineSegments();
}
return FReply::Handled();
}
bool FLandscapeSplineDetails::HasAdjacentLinearSplineElement(ESplineNavigationFlags Flags) const
{
FEdModeLandscape* LandscapeEdMode = GetEditorMode();
if (LandscapeEdMode && LandscapeEdMode->CurrentToolTarget.LandscapeInfo.IsValid() && LandscapeEdMode->CurrentToolTarget.LandscapeInfo->GetCurrentLevelLandscapeProxy(true))
{
// check flags have one direction set
check(FMath::CountBits(static_cast<uint8>(Flags & ESplineNavigationFlags::DirectionMask)) == 1);
return LandscapeEdMode->HasAdjacentLinearSplineConnection(Flags | (IsSegmentSelectModeEnabled() ? ESplineNavigationFlags::SegmentSelectModeEnabled : ESplineNavigationFlags::ControlPointSelectModeEnabled));
}
return false;
}
bool FLandscapeSplineDetails::HasEndLinearSplineElement(ESplineNavigationFlags Flags) const
{
FEdModeLandscape* LandscapeEdMode = GetEditorMode();
if (LandscapeEdMode && LandscapeEdMode->CurrentToolTarget.LandscapeInfo.IsValid() && LandscapeEdMode->CurrentToolTarget.LandscapeInfo->GetCurrentLevelLandscapeProxy(true))
{
// check flags have one direction set
check(FMath::CountBits(static_cast<uint8>(Flags & ESplineNavigationFlags::DirectionMask)) == 1);
return LandscapeEdMode->HasEndLinearSplineConnection(Flags | (IsSegmentSelectModeEnabled() ? ESplineNavigationFlags::SegmentSelectModeEnabled : ESplineNavigationFlags::ControlPointSelectModeEnabled));
}
return false;
}
bool FLandscapeSplineDetails::IsFlipSegmentButtonEnabled() const
{
FEdModeLandscape* LandscapeEdMode = GetEditorMode();
if (LandscapeEdMode && LandscapeEdMode->CurrentToolTarget.LandscapeInfo.IsValid() && LandscapeEdMode->CurrentToolTarget.LandscapeInfo->GetCurrentLevelLandscapeProxy(true))
{
return LandscapeEdMode->HasSelectedSplineSegments();
}
return false;
}
FText FLandscapeSplineDetails::OnGetSplineOwningLandscapeText() const
{
TSet<AActor*> SplineOwners;
FEdModeLandscape* LandscapeEdMode = GetEditorMode();
if (LandscapeEdMode && LandscapeEdMode->CurrentToolTarget.LandscapeInfo.IsValid())
{
LandscapeEdMode->GetSelectedSplineOwners(SplineOwners);
}
FString SplineOwnersStr;
for (AActor* Owner : SplineOwners)
{
if (Owner)
{
if (!SplineOwnersStr.IsEmpty())
{
SplineOwnersStr += ", ";
}
SplineOwnersStr += Owner->GetActorLabel();
}
}
return FText::FromString("Owner: " + SplineOwnersStr);
}
FReply FLandscapeSplineDetails::OnSelectAdjacentLinearSplineElementButtonClicked(ESplineNavigationFlags Flags) const
{
FEdModeLandscape* LandscapeEdMode = GetEditorMode();
if (LandscapeEdMode && LandscapeEdMode->CurrentToolTarget.LandscapeInfo.IsValid() && LandscapeEdMode->CurrentToolTarget.LandscapeInfo->GetCurrentLevelLandscapeProxy(true))
{
// check flags have one direction set
check(FMath::CountBits(static_cast<uint8>(Flags & ESplineNavigationFlags::DirectionMask)) == 1);
LandscapeEdMode->SelectAdjacentLinearSplineElement(Flags | (IsSegmentSelectModeEnabled() ? ESplineNavigationFlags::SegmentSelectModeEnabled : ESplineNavigationFlags::ControlPointSelectModeEnabled));
}
return FReply::Handled();
}
FReply FLandscapeSplineDetails::OnSelectEndLinearSplineElementButtonClicked(ESplineNavigationFlags Flags) const
{
FEdModeLandscape* LandscapeEdMode = GetEditorMode();
if (LandscapeEdMode && LandscapeEdMode->CurrentToolTarget.LandscapeInfo.IsValid() && LandscapeEdMode->CurrentToolTarget.LandscapeInfo->GetCurrentLevelLandscapeProxy(true))
{
// check flags have one direction set
check(FMath::CountBits(static_cast<uint8>(Flags & ESplineNavigationFlags::DirectionMask)) == 1);
LandscapeEdMode->SelectEndLinearSplineElement(Flags | (IsSegmentSelectModeEnabled() ? ESplineNavigationFlags::SegmentSelectModeEnabled : ESplineNavigationFlags::ControlPointSelectModeEnabled));
}
return FReply::Handled();
}
FReply FLandscapeSplineDetails::OnToggleSplineSelectionTypeButtonClicked() const
{
FEdModeLandscape* LandscapeEdMode = GetEditorMode();
if (LandscapeEdMode && LandscapeEdMode->CurrentToolTarget.LandscapeInfo.IsValid() && LandscapeEdMode->CurrentToolTarget.LandscapeInfo->GetCurrentLevelLandscapeProxy(true))
{
IsSegmentSelectModeEnabled() ? LandscapeEdMode->SelectSplineControlPointsFromCurrentSegmentSelection() : LandscapeEdMode->SelectSplineSegmentsFromCurrentControlPointSelection();
}
return FReply::Handled();
}
FReply FLandscapeSplineDetails::OnSelectAllConnectedSplineElementsButtonClicked() const
{
FEdModeLandscape* LandscapeEdMode = GetEditorMode();
if (LandscapeEdMode && LandscapeEdMode->CurrentToolTarget.LandscapeInfo.IsValid() && LandscapeEdMode->CurrentToolTarget.LandscapeInfo->GetCurrentLevelLandscapeProxy(true))
{
IsSegmentSelectModeEnabled() ? LandscapeEdMode->SelectAllConnectedSplineSegments() : LandscapeEdMode->SelectAllConnectedSplineControlPoints();
}
return FReply::Handled();
}
FReply FLandscapeSplineDetails::OnMoveToCurrentLevelButtonClicked()
{
FEdModeLandscape* LandscapeEdMode = GetEditorMode();
if (LandscapeEdMode && LandscapeEdMode->CurrentToolTarget.LandscapeInfo.IsValid() && LandscapeEdMode->CurrentToolTarget.LandscapeInfo->GetCurrentLevelLandscapeProxy(true))
{
LandscapeEdMode->SplineMoveToCurrentLevel();
}
return FReply::Handled();
}
bool FLandscapeSplineDetails::IsMoveToCurrentLevelButtonEnabled() const
{
FEdModeLandscape* LandscapeEdMode = GetEditorMode();
if (LandscapeEdMode && LandscapeEdMode->CurrentToolTarget.LandscapeInfo.IsValid() && LandscapeEdMode->CurrentToolTarget.LandscapeInfo->GetCurrentLevelLandscapeProxy(true))
{
return LandscapeEdMode->CanMoveSplineToCurrentLevel();
}
return false;
}
FReply FLandscapeSplineDetails::OnUpdateSplineMeshLevelsButtonClicked()
{
FEdModeLandscape* LandscapeEdMode = GetEditorMode();
if (LandscapeEdMode && LandscapeEdMode->CurrentToolTarget.LandscapeInfo.IsValid())
{
LandscapeEdMode->UpdateSplineMeshLevels();
}
return FReply::Handled();
}
bool FLandscapeSplineDetails::IsUpdateSplineMeshLevelsButtonEnabled() const
{
FEdModeLandscape* LandscapeEdMode = GetEditorMode();
if (LandscapeEdMode && LandscapeEdMode->CurrentToolTarget.LandscapeInfo.IsValid())
{
return LandscapeEdMode->CurrentToolTarget.LandscapeInfo.IsValid();
}
return false;
}
#undef LOCTEXT_NAMESPACE