#pragma region CPL License /* Nuclex Unreal Module Copyright (C) 2014-2021 Nuclex Development Labs This library is free software; you can redistribute it and/or modify it under the terms of the IBM Common Public License as published by the IBM Corporation; either version 1.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the IBM Common Public License for more details. You should have received a copy of the IBM Common Public License along with this library */ #pragma endregion // CPL License #include "UI/DialogPlayerController.h" #include "NuclexErrors.h" #include #include // --------------------------------------------------------------------------------------------- // ADialogPlayerController::ADialogPlayerController() : EnableDialogInput(true), AutoShowMouse(false), FeedPawnWidgetInteraction(true), ActiveDialog(), widgetInteraction(nullptr), checkedPawn(nullptr), isLeftMouseButtonPressed(false), defaultInputActionsBound(false), leftMouseButtonKey(TEXT("LeftMouseButton")) { // Some alternative defaults (can be overriden in the editor) this->AutoReceiveInput = EAutoReceiveInput::Player0; SetCanBeDamaged(false); this->SpawnCollisionHandlingMethod = ESpawnActorCollisionHandlingMethod::AlwaysSpawn; // Sets defaults appropriate for UI interaction. This can, of course, // be overriden by simply changing the settings in the UE editor. this->bShowMouseCursor = true; this->bEnableClickEvents = true; this->bEnableMouseOverEvents = true; this->bEnableTouchEvents = false; } // --------------------------------------------------------------------------------------------- // void ADialogPlayerController::BindToDefaultInputActions_Implementation() { if(!this->defaultInputActionsBound) { UInputComponent &inputComponent = *this->InputComponent; // Tell Unreal's "input component" to notify us when certain input actions are activated inputComponent.BindAction( TEXT("Accept"), IE_Pressed, this, &ADialogPlayerController::InjectAccept ); inputComponent.BindAction( TEXT("Cancel"), IE_Pressed, this, &ADialogPlayerController::InjectCancel ); inputComponent.BindAction( TEXT("Up"), IE_Pressed, this, &ADialogPlayerController::InjectUp ); inputComponent.BindAction( TEXT("Down"), IE_Pressed, this, &ADialogPlayerController::InjectDown ); inputComponent.BindAction( TEXT("Left"), IE_Pressed, this, &ADialogPlayerController::InjectLeft ); inputComponent.BindAction( TEXT("Right"), IE_Pressed, this, &ADialogPlayerController::InjectRight ); this->defaultInputActionsBound = true; } } // --------------------------------------------------------------------------------------------- // void ADialogPlayerController::InjectAccept() { if(this->EnableDialogInput) { if(IsValid(this->ActiveDialog.GetObject())) { IButtonControllableDialog::Execute_Accept(this->ActiveDialog.GetObject()); } } } // --------------------------------------------------------------------------------------------- // void ADialogPlayerController::InjectCancel() { if(this->EnableDialogInput) { if(IsValid(this->ActiveDialog.GetObject())) { IButtonControllableDialog::Execute_Cancel(this->ActiveDialog.GetObject()); } } } // --------------------------------------------------------------------------------------------- // void ADialogPlayerController::InjectUp() { if(this->EnableDialogInput) { if(IsValid(this->ActiveDialog.GetObject())) { IButtonControllableDialog::Execute_SelectUp(this->ActiveDialog.GetObject()); } } } // --------------------------------------------------------------------------------------------- // void ADialogPlayerController::InjectDown() { if(this->EnableDialogInput) { if(IsValid(this->ActiveDialog.GetObject())) { IButtonControllableDialog::Execute_SelectDown(this->ActiveDialog.GetObject()); } } } // --------------------------------------------------------------------------------------------- // void ADialogPlayerController::InjectLeft() { if(this->EnableDialogInput) { if(IsValid(this->ActiveDialog.GetObject())) { IButtonControllableDialog::Execute_SelectLeft(this->ActiveDialog.GetObject()); } } } // --------------------------------------------------------------------------------------------- // void ADialogPlayerController::InjectRight() { if(this->EnableDialogInput) { if(IsValid(this->ActiveDialog.GetObject())) { IButtonControllableDialog::Execute_SelectRight(this->ActiveDialog.GetObject()); } } } // --------------------------------------------------------------------------------------------- // void ADialogPlayerController::BeginDialogInput_Implementation( const TScriptInterface &targetDialog ) { this->ActiveDialog = targetDialog; if(this->AutoShowMouse) { this->bShowMouseCursor = true; this->bEnableClickEvents = true; this->bEnableMouseOverEvents = true; this->bEnableTouchEvents = false; } } // --------------------------------------------------------------------------------------------- // void ADialogPlayerController::EndDialogInput_Implementation() { if(this->AutoShowMouse) { this->bShowMouseCursor = false; this->bEnableClickEvents = false; this->bEnableMouseOverEvents = false; this->bEnableTouchEvents = false; } this->ActiveDialog = nullptr; } // --------------------------------------------------------------------------------------------- // void ADialogPlayerController::SetupInputComponent() { Super::SetupInputComponent(); // Input actions we always want (independent of game-specific input action naming) { UInputComponent &inputComponent = *this->InputComponent; // Bind mouse input bypassing any actions - this is only used for UI stuff such as // dragging sliders & scrollbars. inputComponent.BindKey( this->leftMouseButtonKey, IE_Pressed, this, &ADialogPlayerController::pointerPressed ); inputComponent.BindKey( this->leftMouseButtonKey, IE_Released, this, &ADialogPlayerController::pointerReleased ); } } // --------------------------------------------------------------------------------------------- // void ADialogPlayerController::EndPlay(const EEndPlayReason::Type endPlayReason) { this->checkedPawn = nullptr; this->widgetInteraction = nullptr; Super::EndPlay(endPlayReason); } // --------------------------------------------------------------------------------------------- // void ADialogPlayerController::OnPossess(APawn *pawn) { Super::OnPossess(pawn); if(this->FeedPawnWidgetInteraction) { updatePawnWidgetInteractionComponent(); // If the mouse button is being held down while the pawn changes, // directly send this state to the new widget interaction component if(this->isLeftMouseButtonPressed) { if(IsValid(this->widgetInteraction)) { this->widgetInteraction->PressPointerKey(this->leftMouseButtonKey); } } } } // --------------------------------------------------------------------------------------------- // void ADialogPlayerController::OnUnPossess() { if(this->isLeftMouseButtonPressed) { if(IsValid(this->widgetInteraction)) { this->widgetInteraction->ReleasePointerKey(this->leftMouseButtonKey); } } this->checkedPawn = nullptr; this->widgetInteraction = nullptr; Super::OnUnPossess(); } // --------------------------------------------------------------------------------------------- // void ADialogPlayerController::pointerPressed() { if(this->FeedPawnWidgetInteraction) { updatePawnWidgetInteractionComponent(); if(IsValid(this->widgetInteraction)) { this->widgetInteraction->PressPointerKey(this->leftMouseButtonKey); } } this->isLeftMouseButtonPressed = true; } // --------------------------------------------------------------------------------------------- // void ADialogPlayerController::pointerReleased() { if(this->FeedPawnWidgetInteraction) { updatePawnWidgetInteractionComponent(); if(IsValid(this->widgetInteraction)) { this->widgetInteraction->ReleasePointerKey(this->leftMouseButtonKey); } } this->isLeftMouseButtonPressed = false; } // --------------------------------------------------------------------------------------------- // void ADialogPlayerController::updatePawnWidgetInteractionComponent() { APawn *pawn = GetPawn(); if(pawn != this->checkedPawn) { this->checkedPawn = pawn; // This shouldn't be possible, but I have no trust in Epic's code and // it will prevent a crash if a null pointer is passed along if(pawn == nullptr) { this->widgetInteraction = nullptr; return; } // Look for widget interaction components in the pawn TArray components; pawn->GetComponents(components); // Unless there's precisely one such component, do nothing switch(components.Num()) { case 0: { this->widgetInteraction = nullptr; break; } case 1: { this->widgetInteraction = components[0]; break; } default: { this->widgetInteraction = nullptr; UE_LOG( LogNuclex, Warning, TEXT("%s - WARN: %s"), TEXT("ADialogPlayerController::updatePawnWidgetInteractionComponent()"), TEXT("Possessed pawn has multiple widget interaction components, ") TEXT("refusing to pick one by random") ); break; } } } } // --------------------------------------------------------------------------------------------- //