// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved. #include "WorldBrowserPrivatePCH.h" #include "Editor/PropertyEditor/Public/IDetailsView.h" #include "Editor/PropertyEditor/Public/PropertyEditing.h" #include "Editor/PropertyEditor/Public/PropertyEditorModule.h" #include "SVectorInputBox.h" #include "SRotatorInputBox.h" #include "SWorldDetails.h" #include "StreamingLevelCollectionModel.h" #include "StreamingLevelCustomization.h" #include "StreamingLevelEdMode.h" #define LOCTEXT_NAMESPACE "WorldBrowser" ///////////////////////////////////////////////////// // FWorldTileDetails FStreamingLevelCustomization::FStreamingLevelCustomization() : bSliderMovement(false) { } TSharedRef FStreamingLevelCustomization::MakeInstance(TSharedRef InWorldModel) { TSharedRef Instance = MakeShareable(new FStreamingLevelCustomization()); Instance->WorldModel = InWorldModel; return Instance; } void FStreamingLevelCustomization::CustomizeDetails(IDetailLayoutBuilder& DetailLayoutBuilder) { IDetailCategoryBuilder& LevelStreamingCategory = DetailLayoutBuilder.EditCategory("LevelStreaming"); // Hide level transform TSharedPtr LevelTransformProperty = DetailLayoutBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(ULevelStreaming, LevelTransform)); DetailLayoutBuilder.HideProperty(LevelTransformProperty); LevelPositionProperty = LevelTransformProperty->GetChildHandle("Translation"); LevelRotationProperty = LevelTransformProperty->GetChildHandle("Rotation"); // Add Position property LevelStreamingCategory.AddCustomRow(LOCTEXT("Position", "Position").ToString()) .NameContent() [ SNew(STextBlock) .Text(LOCTEXT("Position", "Position")) .Font(IDetailLayoutBuilder::GetDetailFont()) ] .ValueContent() .MinDesiredWidth(500) [ SNew(SVectorInputBox) .IsEnabled(this, &FStreamingLevelCustomization::LevelEditTextTransformAllowed) .Font(FEditorStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont"))) .bColorAxisLabels(true) .X(this, &FStreamingLevelCustomization::OnGetLevelPosition, 0) .Y(this, &FStreamingLevelCustomization::OnGetLevelPosition, 1) .Z(this, &FStreamingLevelCustomization::OnGetLevelPosition, 2) .OnXCommitted(this, &FStreamingLevelCustomization::OnSetLevelPosition, 0) .OnYCommitted(this, &FStreamingLevelCustomization::OnSetLevelPosition, 1) .OnZCommitted(this, &FStreamingLevelCustomization::OnSetLevelPosition, 2) ]; // Add Yaw Rotation property LevelStreamingCategory.AddCustomRow(LOCTEXT("Rotation", "Rotation").ToString()) .NameContent() [ SNew(STextBlock) .Text(LOCTEXT("Rotation", "Rotation")) .Font(IDetailLayoutBuilder::GetDetailFont()) ] .ValueContent() .MinDesiredWidth(500) [ SNew(SHorizontalBox) +SHorizontalBox::Slot() .FillWidth(1.f) .Padding(0,2,0,2) [ SNew(SNumericEntryBox) .IsEnabled(this, &FStreamingLevelCustomization::LevelEditTextTransformAllowed) .Font(FEditorStyle::GetFontStyle(TEXT("PropertyWindow.NormalFont"))) .UndeterminedString(LOCTEXT("MultipleValues", "Multiple Values")) //.Delta(90) .AllowSpin(true) .MinValue(0) .MaxValue(360 - 1) .MinSliderValue(0) .MaxSliderValue(360 - 1) .Value(this, &FStreamingLevelCustomization::GetLevelRotation) .OnValueChanged(this, &FStreamingLevelCustomization::OnSetLevelRotation) .OnBeginSliderMovement(this, &FStreamingLevelCustomization::OnBeginLevelRotatonSlider) .OnEndSliderMovement(this, &FStreamingLevelCustomization::OnEndLevelRotatonSlider) .LabelPadding(0) .Label() [ SNumericEntryBox::BuildLabel(LOCTEXT("LevelRotation_Label", "Yaw"), FLinearColor::White, SNumericEntryBox::BlueLabelBackgroundColor) ] ] +SHorizontalBox::Slot() .AutoWidth() [ SNew( SButton ) .Text(LOCTEXT("EditLevelTransform", "Viewport Edit")) .ToolTipText(LOCTEXT("EditLevelToolTip", "Edit level transform in viewport.")) .OnClicked(this, &FStreamingLevelCustomization::OnEditLevelClicked) .IsEnabled(this, &FStreamingLevelCustomization::LevelViewportTransformAllowed) .ContentPadding(1) ] ]; } void FStreamingLevelCustomization::OnSetLevelPosition( float NewValue, ETextCommit::Type CommitInfo, int32 Axis ) { TSharedPtr CollectionModel = WorldModel.Pin(); if (CollectionModel.IsValid()) { FLevelModelList SelectedLevels = CollectionModel->GetSelectedLevels(); for (auto It = SelectedLevels.CreateIterator(); It; ++It) { TSharedPtr LevelModel = StaticCastSharedPtr(*It); if (LevelModel->IsEditable() && LevelModel->GetLevelStreaming().IsValid()) { ULevelStreaming* LevelStreaming = LevelModel->GetLevelStreaming().Get(); // Create transform with new translation FTransform LevelTransform = LevelStreaming->LevelTransform; FVector LevelTraslation = LevelTransform.GetTranslation(); LevelTraslation[Axis] = NewValue; LevelTransform.SetTranslation(LevelTraslation); // Transform level FLevelUtils::SetEditorTransform(LevelStreaming, LevelTransform); } } } } TOptional FStreamingLevelCustomization::OnGetLevelPosition( int32 Axis ) const { float AxisVal = 0.f; if (LevelPositionProperty->GetChildHandle(Axis)->GetValue(AxisVal) == FPropertyAccess::Success) { return AxisVal; } return TOptional(); } void FStreamingLevelCustomization::OnSetLevelRotation( int32 NewValue ) { CachedYawValue = NewValue; if (bSliderMovement) { return; } // Apply rotation when user stops slider drag TSharedPtr CollectionModel = WorldModel.Pin(); if (CollectionModel.IsValid()) { FQuat NewRotaion = FRotator(0.f, (float)CachedYawValue.GetValue(), 0.f).Quaternion(); FLevelModelList SelectedLevels = CollectionModel->GetSelectedLevels(); for (auto It = SelectedLevels.CreateIterator(); It; ++It) { TSharedPtr LevelModel = StaticCastSharedPtr(*It); if (LevelModel->IsEditable() && LevelModel->GetLevelStreaming().IsValid()) { ULevelStreaming* LevelStreaming = LevelModel->GetLevelStreaming().Get(); FTransform LevelTransform = LevelStreaming->LevelTransform; if (LevelTransform.GetRotation() != NewRotaion) { LevelTransform.SetRotation(NewRotaion); FLevelUtils::SetEditorTransform(LevelStreaming, LevelTransform); } } } } } void FStreamingLevelCustomization::OnBeginLevelRotatonSlider() { CachedYawValue = GetLevelRotation(); bSliderMovement = true; } void FStreamingLevelCustomization::OnEndLevelRotatonSlider( int32 NewValue ) { bSliderMovement = false; OnSetLevelRotation(NewValue); } TOptional FStreamingLevelCustomization::GetLevelRotation() const { if (bSliderMovement) { return CachedYawValue; } // If were not using the spin box use the actual transform instead of cached as it may have changed with the view port widget FQuat RotQ; if (LevelRotationProperty->GetValue(RotQ) == FPropertyAccess::Success) { int32 YawValue = FMath::RoundToInt(RotQ.Rotator().Yaw); return YawValue < 0 ? (YawValue + 360) : YawValue; } return TOptional(); } bool FStreamingLevelCustomization::LevelViewportTransformAllowed() const { TSharedPtr CollectionModel = WorldModel.Pin(); if (CollectionModel.IsValid() && CollectionModel->IsOneLevelSelected()) { auto SelectedLevel = CollectionModel->GetSelectedLevels()[0]; return SelectedLevel->IsEditable() && SelectedLevel->IsVisible(); } return false; } bool FStreamingLevelCustomization::LevelEditTextTransformAllowed() const { TSharedPtr CollectionModel = WorldModel.Pin(); if (!CollectionModel.IsValid() || !CollectionModel->AreAnySelectedLevelsEditable()) { return false; } auto LevelModel = StaticCastSharedPtr(CollectionModel->GetSelectedLevels()[0]); ULevelStreaming* LevelStreaming = LevelModel->GetLevelStreaming().Get(); auto* ActiveMode = static_cast( GLevelEditorModeTools().GetActiveMode(FBuiltinEditorModes::EM_StreamingLevel) ); if (ActiveMode && ActiveMode->IsEditing(LevelStreaming) == true) { return false; } return CollectionModel->AreAnySelectedLevelsEditable(); } FReply FStreamingLevelCustomization::OnEditLevelClicked() { TSharedPtr CollectionModel = WorldModel.Pin(); if (!CollectionModel.IsValid() || !CollectionModel->AreAnySelectedLevelsEditable()) { return FReply::Handled(); } auto LevelModel = StaticCastSharedPtr(CollectionModel->GetSelectedLevels()[0]); ULevelStreaming* LevelStreaming = LevelModel->GetLevelStreaming().Get(); if (!LevelStreaming) { return FReply::Handled(); } if (!GLevelEditorModeTools().IsModeActive(FBuiltinEditorModes::EM_StreamingLevel)) { // Activate Level Mode if it was not active GLevelEditorModeTools().ActivateMode(FBuiltinEditorModes::EM_StreamingLevel); } auto* ActiveMode = GLevelEditorModeTools().GetActiveModeTyped(FBuiltinEditorModes::EM_StreamingLevel); check(ActiveMode != NULL); if (ActiveMode->IsEditing(LevelStreaming) == true) { // Toggle this mode off if already editing this level GLevelEditorModeTools().DeactivateMode(FBuiltinEditorModes::EM_StreamingLevel); // ActiveMode is now invalid } else { // Set the level we now want to edit ActiveMode->SetLevel(LevelStreaming); } return FReply::Handled(); } #undef LOCTEXT_NAMESPACE