// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2016. #include "FMODStudioEditorPrivatePCH.h" #include "SFMODEventEditorPanel.h" #include "FMODStudioModule.h" #include "FMODUtils.h" #include "Input/Reply.h" #include "SNumericEntryBox.h" #include "SExpandableArea.h" #include "fmod_studio.hpp" #define LOCTEXT_NAMESPACE "FMODEventEditor" SFMODEventEditorPanel::~SFMODEventEditorPanel() { } void SFMODEventEditorPanel::Construct(const FArguments& InArgs) { FMODEventEditorPtr = InArgs._FMODEventEditor; FMOD::Studio::EventDescription* EventDescription = FMODEventEditorPtr.Pin()->GetEventDescription(); TSharedRef ToolbarBorder = ConstructToolbar(EventDescription); TSharedRef InfoArea = ConstructInfo(EventDescription); TSharedRef ParametersArea = ConstructParameters(EventDescription); TSharedRef UserPropertiesArea = ConstructUserProperties(EventDescription); TSharedRef ChildWidget = SNew(SVerticalBox) + SVerticalBox::Slot() .AutoHeight() .Padding(0.0f, 3.0f) [ InfoArea ] + SVerticalBox::Slot() .AutoHeight() .Padding(0.0f, 3.0f) [ ParametersArea ] + SVerticalBox::Slot() .AutoHeight() .Padding(0.0f, 3.0f) [ UserPropertiesArea ]; ChildSlot [ SNew(SVerticalBox) + SVerticalBox::Slot() .AutoHeight() .Padding(0.0f, 3.0f) [ ToolbarBorder ] + SVerticalBox::Slot() .FillHeight(1.0f) [ SNew(SScrollBox) + SScrollBox::Slot() .Padding(0.0f) [ SNew(SVerticalBox) + SVerticalBox::Slot() .AutoHeight() .Padding(0.0f) [ ChildWidget ] ] ] ]; } TSharedRef SFMODEventEditorPanel::ConstructToolbar(FMOD::Studio::EventDescription* EventDescription) { float MinDistance = 0.0f; float MaxDistance = 0.0f; int32 EventLengthMS = 0; bool bIsOneshot = false, bIsStream = false, bIs3D = false; if (EventDescription != nullptr) { EventDescription->getMinimumDistance(&MinDistance); EventDescription->getMaximumDistance(&MaxDistance); EventDescription->getLength(&EventLengthMS); EventDescription->isOneshot(&bIsOneshot); EventDescription->isStream(&bIsStream); EventDescription->is3D(&bIs3D); } const FTimespan EventLength = FTimespan::FromMilliseconds((double)EventLengthMS); const FString EventLengthString = EventLength.GetHours() <= 0 ? EventLength.ToString(TEXT("%m:%s.%f")) : EventLength.ToString(TEXT("%h:%m:%s.%f")); const FText RadiusText = FText::Format(LOCTEXT("RadiusFormat", "Distance Attenuation: {0}m to {1}m"), FText::AsNumber(MinDistance), FText::AsNumber(MaxDistance)); const FText LengthText = FText::Format(LOCTEXT("LengthFormat", "Length: {0}"), FText::FromString(EventLengthString)); FText EventInfoText; if (bIs3D && bIsOneshot) { EventInfoText = FText::Format(LOCTEXT("RadiusLengthFormat", "{0} - {1}"), RadiusText, LengthText); } else if (!bIs3D && bIsOneshot) { EventInfoText = LengthText; } else if (bIs3D && !bIsOneshot) { EventInfoText = RadiusText; } return SNew(SBorder) .BorderImage(FEditorStyle::Get().GetBrush("ToolPanel.GroupBorder")) .Padding(6.0f) .Content() [ SNew(SHorizontalBox) + SHorizontalBox::Slot() .AutoWidth() .Padding(0.0f, 0.0f, 2.0f, 0.0f) .VAlign(VAlign_Center) .HAlign(HAlign_Left) [ SNew(SButton) .VAlign(VAlign_Center) .Text(LOCTEXT("Play", "Play")) .ContentPadding(4) .OnClicked(this, &SFMODEventEditorPanel::OnClickedPlay) ] + SHorizontalBox::Slot() .AutoWidth() .Padding(2.0f, 0.0f) .VAlign(VAlign_Center) .HAlign(HAlign_Left) [ SNew(SButton) .Text(LOCTEXT("Pause", "Pause")) .ContentPadding(4) .OnClicked(this, &SFMODEventEditorPanel::OnClickedPause) ] + SHorizontalBox::Slot() .AutoWidth() .Padding(2.0f, 0.0f) .VAlign(VAlign_Center) .HAlign(HAlign_Left) [ SNew(SButton) .VAlign(VAlign_Center) .Text(LOCTEXT("Stop", "Stop")) .ContentPadding(4) .OnClicked(this, &SFMODEventEditorPanel::OnClickedStop) ] + SHorizontalBox::Slot() .FillWidth(1.0f) .Padding(2.0f, 0.0f) .VAlign(VAlign_Center) .HAlign(HAlign_Right) [ SNew(STextBlock) .Text(EventInfoText) ] ]; } void AddTextField(TSharedRef& InfoBox, const TCHAR* Name, const FText& Value) { InfoBox->AddSlot() .Padding(4.0f, 3.0f) [ SNew(SHorizontalBox) + SHorizontalBox::Slot() .FillWidth(0.3f) [ SNew(STextBlock) .Text(FText::FromString(Name)) ] + SHorizontalBox::Slot() [ SNew(SEditableText) .Text(Value) .IsReadOnly(true) ] ]; } void AddBoolField(TSharedRef& InfoBox, const TCHAR* Name, bool bValue) { AddTextField(InfoBox, Name, bValue ? LOCTEXT("True","True") : LOCTEXT("False","False")); } void AddFloatField(TSharedRef& InfoBox, const TCHAR* Name, float Value) { AddTextField(InfoBox, Name, FText::AsNumber(Value)); } TSharedRef MakeBox(TSharedRef& InfoBox, const FText& Value) { return SNew(SExpandableArea) .AreaTitle(Value) .InitiallyCollapsed(false) .BodyContent() [ SNew(SBorder) .BorderImage(FCoreStyle::Get().GetBrush("NoBorder")) .Padding(4.0f) .Content() [ InfoBox ] ]; } TSharedRef SFMODEventEditorPanel::ConstructInfo(FMOD::Studio::EventDescription* EventDescription) { TSharedRef InfoBox = SNew(SVerticalBox); if (EventDescription != nullptr) { FString EventPath = FMODUtils::GetPath(EventDescription); FGuid Guid = FMODUtils::GetID(EventDescription); int Length = 0.0f; float MinDist = 0.0f; float MaxDist = 0.0f; EventDescription->getLength(&Length); EventDescription->getMinimumDistance(&MinDist); EventDescription->getMaximumDistance(&MaxDist); bool bOneShot = false; bool bStream = false; bool b3D = false; EventDescription->isOneshot(&bOneShot); EventDescription->isStream(&bStream); EventDescription->is3D(&b3D); AddTextField(InfoBox, TEXT("Path"), FText::FromString(EventPath)); AddTextField(InfoBox, TEXT("Guid"), FText::FromString(Guid.ToString(EGuidFormats::DigitsWithHyphensInBraces))); AddBoolField(InfoBox, TEXT("OneShot"), bOneShot); AddBoolField(InfoBox, TEXT("Streaming"), bStream); AddBoolField(InfoBox, TEXT("3D"), b3D); AddFloatField(InfoBox, TEXT("Length"), static_cast(Length)); if (b3D) { AddFloatField(InfoBox, TEXT("Min Dist"), MinDist); AddFloatField(InfoBox, TEXT("Max Dist"), MaxDist); } } return MakeBox(InfoBox, LOCTEXT("EventInfo", "Event Info")); } TSharedRef SFMODEventEditorPanel::ConstructParameters(FMOD::Studio::EventDescription* EventDescription) { auto EventEditor = FMODEventEditorPtr.Pin(); TSharedRef ParametersBox = SNew(SVerticalBox); FNumberFormattingOptions Options; Options.MinimumFractionalDigits = 1; if (EventDescription != nullptr) { int32 ParameterCount; EventDescription->getParameterCount(&ParameterCount); for (int32 ParamIdx = 0; ParamIdx < ParameterCount; ParamIdx++) { FMOD_STUDIO_PARAMETER_DESCRIPTION Parameter; EventDescription->getParameterByIndex(ParamIdx, &Parameter); EventEditor->GetParameterValues().Add(Parameter.minimum); const FString ParameterName = Parameter.type == FMOD_STUDIO_PARAMETER_GAME_CONTROLLED ? FString(UTF8_TO_TCHAR(Parameter.name)) : FMODUtils::ParameterTypeToString(Parameter.type); const FText ToolTipText = FText::Format(LOCTEXT("ParameterTooltipFormat", "{0} (Min Value: {1} - Max Value: {2})"), FText::FromString(ParameterName), FText::AsNumber(Parameter.minimum, &Options), FText::AsNumber(Parameter.maximum, &Options)); ParametersBox->AddSlot() .Padding(4.0f, 2.0f) [ SNew(SHorizontalBox) .ToolTipText(ToolTipText) + SHorizontalBox::Slot() .FillWidth(0.3f) [ SNew(STextBlock) .Text(FText::FromString(ParameterName)) ] + SHorizontalBox::Slot() .MaxWidth(200.0f) [ SNew(SNumericEntryBox) .Value(this, &SFMODEventEditorPanel::GetParameterValue, ParamIdx) .OnValueChanged(this, &SFMODEventEditorPanel::OnParameterValueChanged, ParamIdx) .AllowSpin(true) .MinValue(Parameter.minimum) .MaxValue(Parameter.maximum) .MinSliderValue(Parameter.minimum) .MaxSliderValue(Parameter.maximum) .Delta(0.01f) ] ]; } } return MakeBox(ParametersBox, LOCTEXT("EventParameters", "Event Parameters")); } TSharedRef SFMODEventEditorPanel::ConstructUserProperties(FMOD::Studio::EventDescription* EventDescription) { TSharedRef UserPropertiesBox = SNew(SVerticalBox); if (EventDescription != nullptr) { int32 UserPropertyCount; EventDescription->getUserPropertyCount(&UserPropertyCount); for (int32 PropertyIdx = 0; PropertyIdx < UserPropertyCount; PropertyIdx++) { FMOD_STUDIO_USER_PROPERTY UserProperty; EventDescription->getUserPropertyByIndex(PropertyIdx, &UserProperty); FText PropertyText; switch (UserProperty.type) { case FMOD_STUDIO_USER_PROPERTY_TYPE_INTEGER: PropertyText = FText::AsNumber(UserProperty.intValue); break; case FMOD_STUDIO_USER_PROPERTY_TYPE_BOOLEAN: PropertyText = UserProperty.boolValue ? LOCTEXT("True", "True") : LOCTEXT("False", "False"); break; case FMOD_STUDIO_USER_PROPERTY_TYPE_FLOAT: PropertyText = FText::AsNumber(UserProperty.floatValue); break; case FMOD_STUDIO_USER_PROPERTY_TYPE_STRING: PropertyText = FText::FromString(UTF8_TO_TCHAR(UserProperty.stringValue)); break; } FString UserName(UTF8_TO_TCHAR(UserProperty.name)); AddTextField(UserPropertiesBox, *UserName, PropertyText); } } return MakeBox(UserPropertiesBox, LOCTEXT("EventUserProperties", "Event User Properties")); } FReply SFMODEventEditorPanel::OnClickedPlay() { FMODEventEditorPtr.Pin()->PlayEvent(); return FReply::Handled(); } FReply SFMODEventEditorPanel::OnClickedStop() { FMODEventEditorPtr.Pin()->StopEvent(); return FReply::Handled(); } FReply SFMODEventEditorPanel::OnClickedPause() { FMODEventEditorPtr.Pin()->PauseEvent(); return FReply::Handled(); } void SFMODEventEditorPanel::OnParameterValueChanged(float NewValue, int32 ParameterIdx) { FMODEventEditorPtr.Pin()->SetParameterValue(ParameterIdx, NewValue); } TOptional SFMODEventEditorPanel::GetParameterValue(int32 ParameterIdx) const { return FMODEventEditorPtr.Pin()->GetParameterValues()[ParameterIdx]; } #undef LOC_NAMESPACE