diff --git a/Source/StudyFrameworkPlugin/Private/GazeTracking/SFGazeTracker.cpp b/Source/StudyFrameworkPlugin/Private/GazeTracking/SFGazeTracker.cpp index 8c49fba6eada45d876025ce555140d5941a524fc..7d3b8965de9a6d8796e72712d82c959ce157e07c 100644 --- a/Source/StudyFrameworkPlugin/Private/GazeTracking/SFGazeTracker.cpp +++ b/Source/StudyFrameworkPlugin/Private/GazeTracking/SFGazeTracker.cpp @@ -90,6 +90,9 @@ FGazeRay USFGazeTracker::GetWorldGazeDirection() FGazeRay LocalGazeRay = GetLocalGazeDirection(); UWorld* World = USFGameInstance::Get()->GetWorld(); + if (!World->GetFirstPlayerController()) { + return FGazeRay(); + } //the gaze ray is relative to the HMD const APlayerCameraManager* CamManager = World->GetFirstPlayerController()-> diff --git a/Source/StudyFrameworkPlugin/Private/HUD/SFMasterHUD.cpp b/Source/StudyFrameworkPlugin/Private/HUD/SFMasterHUD.cpp index cc0665801528c6fd388721b29a92a018f7baa04e..db413bc880334a57e71cb5687d5284377c756608 100644 --- a/Source/StudyFrameworkPlugin/Private/HUD/SFMasterHUD.cpp +++ b/Source/StudyFrameworkPlugin/Private/HUD/SFMasterHUD.cpp @@ -38,7 +38,7 @@ void ASFMasterHUD::BeginPlay() //is called also every time the map is changed (a new condition is loaded) Super::BeginPlay(); - if(!USFGameInstance::Get()->GetExperimenterViewConfig().bShowHUD) + if (USFGameInstance::Get()->GetStudySetup() && !USFGameInstance::Get()->GetExperimenterViewConfig().bShowHUD) { return; } @@ -78,7 +78,7 @@ void ASFMasterHUD::BeginPlay() HUDWidget->AddToViewport(); } } - + FHUDSavedData& Data = USFGameInstance::Get()->HUDSavedData; @@ -119,7 +119,7 @@ void ASFMasterHUD::BeginPlay() HUDWidget->GetNextButton()->OnClicked.AddDynamic(this, &ASFMasterHUD::OnNextButtonPressed); HUDWidget->GetShowConditionsButton()->OnClicked.AddDynamic(this, &ASFMasterHUD::OnShowConditionsButtonPressed); - if(USFGameInstance::Get()->GetExperimenterViewConfig().bShowConditionsPanelByDefault) + if (USFGameInstance::Get()->GetStudySetup() && USFGameInstance::Get()->GetExperimenterViewConfig().bShowConditionsPanelByDefault) { OnShowConditionsButtonPressed(); } diff --git a/Source/StudyFrameworkPlugin/Private/Help/SFCustomDialog.cpp b/Source/StudyFrameworkPlugin/Private/Help/SFCustomDialog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0db6ba11745e383153a158c9a5ded180e9a45137 --- /dev/null +++ b/Source/StudyFrameworkPlugin/Private/Help/SFCustomDialog.cpp @@ -0,0 +1,171 @@ +// Copyright Epic Games, Inc. All Rights Reserved. +//This file is changed from an Unreal Engine file + +#include "Help/SFCustomDialog.h" + +#include "HAL/PlatformApplicationMisc.h" + +//#include "EditorStyleSet.h" +//#include "Framework/Docking/TabManager.h" +#include "Framework/Application/SlateApplication.h" +#include "Logging/LogMacros.h" +#include "Styling/SlateBrush.h" +#include "Widgets/Images/SImage.h" +#include "Widgets/Input/SButton.h" +#include "Widgets/Text/STextBlock.h" +#include "Widgets/Layout/SSpacer.h" +#include "Widgets/Layout/SBox.h" +#include "Widgets/Layout/SScrollBox.h" +#include "Widgets/Layout/SUniformGridPanel.h" +#include "Widgets/SBoxPanel.h" + +DEFINE_LOG_CATEGORY_STATIC(LogCustomDialog, Log, All); + +void SFCustomDialog::Construct(const FArguments& InArgs) +{ + UE_LOG(LogCustomDialog, Log, TEXT("Dialog displayed:"), *InArgs._Title.ToString()); + + check(InArgs._Buttons.Num() > 0); + + OnClosed = InArgs._OnClosed; + + TSharedPtr<SHorizontalBox> ContentBox; + TSharedPtr<SHorizontalBox> ButtonBox; + + SWindow::Construct(SWindow::FArguments() + .Title(InArgs._Title) + .SizingRule(ESizingRule::Autosized) + .SupportsMaximize(false) + .SupportsMinimize(false) + [ + SNew(SBorder) + .Padding(4.f) + //.BorderImage(FEditorStyle::GetBrush("ToolPanel.GroupBorder")) //!!! + [ + SNew(SVerticalBox) + + SVerticalBox::Slot() + .FillHeight(1.0f) + [ + SAssignNew(ContentBox, SHorizontalBox) + ] + + SVerticalBox::Slot() + .VAlign(VAlign_Center) + .AutoHeight() + [ + SAssignNew(ButtonBox, SHorizontalBox) + ] + ] + ]); + + if (InArgs._IconBrush.IsValid()) + { + const FSlateBrush* ImageBrush = nullptr;// FEditorStyle::GetBrush(InArgs._IconBrush); //!!! + if (ImageBrush != nullptr) + { + ContentBox->AddSlot() + .AutoWidth() + .VAlign(VAlign_Center) + .HAlign(HAlign_Left) + .Padding(0, 0, 8, 0) + [ + SNew(SImage) + .Image(ImageBrush) + ]; + } + } + + if (InArgs._UseScrollBox) + { + ContentBox->AddSlot() + [ + SNew(SBox) + .MaxDesiredHeight(InArgs._ScrollBoxMaxHeight) + [ + SNew(SScrollBox) + + SScrollBox::Slot() + [ + InArgs._DialogContent.ToSharedRef() + ] + ] + ]; + } + else + { + ContentBox->AddSlot() + .FillWidth(1.0f) + .VAlign(VAlign_Center) + .HAlign(HAlign_Left) + [ + InArgs._DialogContent.ToSharedRef() + ]; + } + + ButtonBox->AddSlot() + .AutoWidth() + [ + SNew(SSpacer) + .Size(FVector2D(20.0f, 1.0f)) + ]; + + TSharedPtr<SUniformGridPanel> ButtonPanel; + + ButtonBox->AddSlot() + .FillWidth(1.0f) + .VAlign(VAlign_Center) + .HAlign(HAlign_Right) + [ + SAssignNew(ButtonPanel, SUniformGridPanel) + //.SlotPadding(FEditorStyle::GetMargin("StandardDialog.SlotPadding")) //!!! + //.MinDesiredSlotWidth(FEditorStyle::GetFloat("StandardDialog.MinDesiredSlotWidth")) //!!! + //.MinDesiredSlotHeight(FEditorStyle::GetFloat("StandardDialog.MinDesiredSlotHeight")) //!!! + ]; + + for (int32 i = 0; i < InArgs._Buttons.Num(); ++i) + { + const FButton& Button = InArgs._Buttons[i]; + + ButtonPanel->AddSlot(ButtonPanel->GetChildren()->Num(), 0) + [ + SNew(SButton) + .OnClicked(FOnClicked::CreateSP(this, &SFCustomDialog::OnButtonClicked, Button.OnClicked, i)) + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .VAlign(VAlign_Center) + .HAlign(HAlign_Center) + [ + SNew(STextBlock) + .Text(Button.ButtonText) + ] + ] + ]; + } +} + +int32 SFCustomDialog::ShowModal() +{ + FSlateApplication::Get().AddModalWindow(StaticCastSharedRef<SWindow>(this->AsShared()), FGlobalTabmanager::Get()->GetRootWindow()); + + return LastPressedButton; +} + +void SFCustomDialog::Show() +{ + TSharedRef<SWindow> Window = FSlateApplication::Get().AddWindow(StaticCastSharedRef<SWindow>(this->AsShared()), true); + + if (OnClosed.IsBound()) + { + Window->GetOnWindowClosedEvent().AddLambda([this](const TSharedRef<SWindow>& Window) { OnClosed.Execute(); }); + } +} + +/** Handle the button being clicked */ +FReply SFCustomDialog::OnButtonClicked(FSimpleDelegate OnClicked, int32 ButtonIndex) +{ + LastPressedButton = ButtonIndex; + + FSlateApplication::Get().RequestDestroyWindow(StaticCastSharedRef<SWindow>(this->AsShared())); + + OnClicked.ExecuteIfBound(); + return FReply::Handled(); +} diff --git a/Source/StudyFrameworkPlugin/Private/Help/SFUtils.cpp b/Source/StudyFrameworkPlugin/Private/Help/SFUtils.cpp index 2b9003499eb5ba442907d445dfe55a088a9cced0..84b64e24d5384e064c2a863e8d8eed0ea6308f7e 100644 --- a/Source/StudyFrameworkPlugin/Private/Help/SFUtils.cpp +++ b/Source/StudyFrameworkPlugin/Private/Help/SFUtils.cpp @@ -32,12 +32,12 @@ void FSFUtils::OpenMessageBox(const FString Text, const bool bError/*=false*/) int FSFUtils::OpenCustomDialog(const FString& Title, const FString& Content, const TArray<FString>& Buttons) { - TArray<SCustomDialog::FButton> Buttons_Text; + TArray<SFCustomDialog::FButton> Buttons_Text; for (const FString& Btn : Buttons) { - Buttons_Text.Add(SCustomDialog::FButton(FText::FromString(Btn))); + Buttons_Text.Add(SFCustomDialog::FButton(FText::FromString(Btn))); } - TSharedRef<SCustomDialog> Dialog = SNew(SCustomDialog) + TSharedRef<SFCustomDialog> Dialog = SNew(SFCustomDialog) .Title(FText(FText::FromString(Title))) .DialogContent(SNew(STextBlock).Text(FText::FromString(Content))) .Buttons(Buttons_Text); @@ -57,11 +57,11 @@ int FSFUtils::OpenCustomDialogText(const FString& Title, const FString& Content, VBox->AddSlot().AttachWidget(ContentWidget); VBox->AddSlot().AttachWidget(Border); - TSharedRef<SCustomDialog> Dialog = SNew(SCustomDialog) + TSharedRef<SFCustomDialog> Dialog = SNew(SFCustomDialog) .Title(FText(FText::FromString(Title))) .DialogContent(VBox) .Buttons({ - SCustomDialog::FButton(FText::FromString("Submit")) + SFCustomDialog::FButton(FText::FromString("Submit")) }); int Result = Dialog->ShowModal(); diff --git a/Source/StudyFrameworkPlugin/Private/Logging/SFLogObject.cpp b/Source/StudyFrameworkPlugin/Private/Logging/SFLogObject.cpp index a0952da29d320ad9d27aa5e6c8d8d4d1cc41d57e..75162133a6fe0aa4527a0957ee7b0c72cdf059fa 100644 --- a/Source/StudyFrameworkPlugin/Private/Logging/SFLogObject.cpp +++ b/Source/StudyFrameworkPlugin/Private/Logging/SFLogObject.cpp @@ -158,6 +158,10 @@ void USFLogObject::WriteGazeTrackingLogToFile() { return; } + if (!USFGameInstance::Get()->GetWorld()->GetFirstPlayerController()) { + return; + } + if (!USFGameInstance::Get()->GetLogObject()->bGazingLoggingFileCreated) { USFGameInstance::Get()->GetLogObject()->CreateGazeTrackingLogFile(); diff --git a/Source/StudyFrameworkPlugin/Public/Help/SFCustomDialog.h b/Source/StudyFrameworkPlugin/Public/Help/SFCustomDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..c3929e0ae81d915a98b7b3afd24d2516033fbfd8 --- /dev/null +++ b/Source/StudyFrameworkPlugin/Public/Help/SFCustomDialog.h @@ -0,0 +1,86 @@ +// Copyright Epic Games, Inc. All Rights Reserved. +//This file is changed from an Unreal Engine file + +#pragma once + +#include "Widgets/SWindow.h" + +/** This is a custom dialog class, which allows any Slate widget to be used as the contents, + * with any number of buttons that have any text. + * It also supports adding a custom icon to the dialog. + * Usage: + * TSharedRef<SCustomDialog> HelloWorldDialog = SNew(SCustomDialog) + .Title(FText(LOCTEXT("HelloWorldTitleExample", "Hello, World!"))) + .DialogContent( SNew(SImage).Image(FName(TEXT("Hello")))) + .Buttons({ + SCustomDialog::FButton(LOCTEXT("OK", "OK")), + SCustomDialog::FButton(LOCTEXT("Cancel", "Cancel")) + }); + + // returns 0 when OK is pressed, 1 when Cancel is pressed, -1 if the window is closed + const int ButtonPressed = HelloWorldDialog->ShowModal(); + */ +class STUDYFRAMEWORKPLUGIN_API SFCustomDialog : public SWindow +{ +public: + struct FButton + { + FButton(const FText& InButtonText, const FSimpleDelegate& InOnClicked = FSimpleDelegate()) + : ButtonText(InButtonText), + OnClicked(InOnClicked) + { + } + + FText ButtonText; + FSimpleDelegate OnClicked; + }; + + SLATE_BEGIN_ARGS(SFCustomDialog) + : _UseScrollBox(true) + , _ScrollBoxMaxHeight(300) + { + _AccessibleParams = FAccessibleWidgetData(EAccessibleBehavior::Auto); + } + /** Title to display for the dialog. */ + SLATE_ARGUMENT(FText, Title) + + /** Optional icon to display in the dialog. (default: none) */ + SLATE_ARGUMENT(FName, IconBrush) + + /** Should this dialog use a scroll box for over-sized content? (default: true) */ + SLATE_ARGUMENT(bool, UseScrollBox) + + /** Max height for the scroll box (default: 300) */ + SLATE_ARGUMENT(int32, ScrollBoxMaxHeight) + + /** The buttons that this dialog should have. One or more buttons must be added.*/ + SLATE_ARGUMENT(TArray<FButton>, Buttons) + + /** Content for the dialog */ + SLATE_ARGUMENT(TSharedPtr<SWidget>, DialogContent) + + /** Event triggered when the dialog is closed, either because one of the buttons is pressed, or the windows is closed. */ + SLATE_EVENT(FSimpleDelegate, OnClosed) + + SLATE_END_ARGS() + + void Construct(const FArguments& InArgs); + + /** Show the dialog. + * This method will return immediately. + */ + void Show(); + + /** Show a modal dialog. Will block until an input is received. + * Returns the index of the button that was pressed. + */ + int32 ShowModal(); + +private: + FReply OnButtonClicked(FSimpleDelegate OnClicked, int32 ButtonIndex); + + /** The index of the button that was pressed last. */ + int32 LastPressedButton = -1; + + FSimpleDelegate OnClosed; +}; \ No newline at end of file diff --git a/Source/StudyFrameworkPlugin/Public/Help/SFUtils.h b/Source/StudyFrameworkPlugin/Public/Help/SFUtils.h index c70caa2455df661e1bb72ec19a26fc4b29f51000..d51c168a70b224c3c68505780854c3b74073bde5 100644 --- a/Source/StudyFrameworkPlugin/Public/Help/SFUtils.h +++ b/Source/StudyFrameworkPlugin/Public/Help/SFUtils.h @@ -4,7 +4,7 @@ #include "Core.h" #include "SFParticipant.h" -#include "Dialogs/CustomDialog.h" +#include "SFCustomDialog.h" class FJsonObject;