// Project Lab - NHTV Igad #include "UnrealProject.h" #include "SubMenu.h" #include "PlayerControllerBase.h" #include "MenuButton.h" #include "DefaultGameInstance.h" #include "MenuScreenBase.h" #include "EffectFunctionLibrary.h" #include "ScreenOverlay.h" USoundBase* confirmAudioClass; USoundBase* backAudioClass; USoundBase* selectionChangedAudioClass; USoundBase* clickAudioClass; USubMenu::USubMenu(const FObjectInitializer& init) { selectionChangedAudioClass = ConstructorHelpers::FObjectFinder(TEXT("/Game/Assets/GUI/Components/InterfaceSounds/Select2")).Object; backAudioClass = ConstructorHelpers::FObjectFinder(TEXT("/Game/Assets/GUI/Components/InterfaceSounds/Select0")).Object; confirmAudioClass = ConstructorHelpers::FObjectFinder(TEXT("/Game/Assets/GUI/Components/InterfaceSounds/Select1")).Object; clickAudioClass = ConstructorHelpers::FObjectFinder(TEXT("/Game/Assets/Sound/T_SkillDrop")).Object; } void USubMenu::NativeConstruct() { m_focus = false; m_layoutDirection = 0; container = Cast(WidgetTree->FindWidget("SubMenuContainer")); if(!container) { container = Cast(GetRootWidget()); if(!container) { GERROR("No \"Container\" found in widget " + GetName() + ", root widget was not a PanelWidget"); } } Super::NativeConstruct(); m_selectedItem = 0; RescanItems(); } void USubMenu::NativeDestruct() { Super::NativeDestruct(); } void USubMenu::NativeTick(const FGeometry& MyGeometry, float InDeltaTime) { Super::NativeTick(MyGeometry, InDeltaTime); if(HasFocus()) { for(UMenuItemBase* item : m_items) { item->FocusTick(InDeltaTime); } } } void USubMenu::m_ScanContainer(UWidget* widget, int32 depth /*= 0*/) { // Loop through panel widgets UPanelWidget* panel = Cast(widget); if(panel) { for(int32 i = 0; i < panel->GetChildrenCount(); i++) { m_ScanContainer(panel->GetChildAt(i), depth+1); } return; } // Process Menu items UMenuItemBase* item = Cast(widget); if(item) { bool hidden = item->GetVisibility() == ESlateVisibility::Hidden || item->GetVisibility() == ESlateVisibility::Collapsed; if(!hidden) { m_items.Add(item); // Assign item to a submenu item->m_subMenu = this; } return; } UPanelUserWidget* puw = Cast(widget); if(puw) { m_ScanContainer(puw->GetRootWidget()); return; } } void USubMenu::RescanItems() { m_items.SetNum(0); if(container) { if(Cast(container)) { m_layoutDirection = 1; } else { m_layoutDirection = 0; } // Scan for buttons m_ScanContainer(container); int32 childCount = m_items.Num(); // Clamp selection m_selectedItem = FMath::Clamp(m_selectedItem, 0, childCount - 1); // Set active selection for(int32 i = 0; i < childCount; i++) { UMenuItemBase* item = m_items[i]; item->index = i; if(i == m_selectedItem) { item->NativeOnSelectionChanged(true, true); } else { item->NativeOnSelectionChanged(false, true); } } // Reselect single items if(childCount == 1) { m_items[0]->NativeOnSelectionChanged(false, true); m_items[0]->NativeOnSelectionChanged(true, true); } if(childCount > 0) { // Selection event onItemSelected.Broadcast(m_items[m_selectedItem]); } } else { GWWARNING(L"SubMenu Container not set"); return; } } void USubMenu::CloseSubMenu() { if(m_screen) m_screen->CloseSubMenu(this); } void USubMenu::OnEnter(class UMenuScreenBase* screen) { check(screen); m_screen = screen; SetButtonHints(); onOpened.Broadcast(); m_SetFocus(true); } void USubMenu::OnLeave() { onClosed.Broadcast(); m_screen = nullptr; m_SetFocus(false); } bool USubMenu::HasFocus() const { return m_focus; } void USubMenu::OnSuspend(USubMenu* newSubMenu, bool loseFocus) { if(loseFocus) m_SetFocus(false); onSuspend.Broadcast(); } void USubMenu::OnRestore(USubMenu* removedMenu) { SetButtonHints(); m_SetFocus(true); onRestore.Broadcast(); } class UButtonHintBar* USubMenu::GetButtonHintBar() const { return GetScreen()->GetButtonHintBar(); } class UCharacterSettings* USubMenu::GetCharacterSettings() const { return GetGameInstance()->GetCharacterSettings(); } class UPrefs* USubMenu::GetPrefs() const { return GetGameInstance()->GetPrefs(); } class UDefaultGameInstance* USubMenu::GetGameInstance() const { return Cast(GetWorld()->GetGameInstance()); } void USubMenu::NativeOnMenuAction(EMenuActionBinding binding) { if(m_items.Num() > 0) m_items[m_selectedItem]->NativeOnMenuAction(binding); switch(binding) { case EMenuActionBinding::Down: if(m_items.Num() > 0 && m_layoutDirection == 0) SelectNewItemByIndex(FMath::Clamp(m_selectedItem + 1, 0, GetNumItems()-1), true); break; case EMenuActionBinding::Up: if(m_items.Num() > 0 && m_layoutDirection == 0) SelectNewItemByIndex(FMath::Clamp(m_selectedItem - 1, 0, GetNumItems()-1), true); break; case EMenuActionBinding::Left: if(m_items.Num() > 0 && m_layoutDirection == 1) SelectNewItemByIndex(FMath::Clamp(m_selectedItem - 1, 0, GetNumItems() - 1), true); break; case EMenuActionBinding::Right: if(m_items.Num() > 0 && m_layoutDirection == 1) SelectNewItemByIndex(FMath::Clamp(m_selectedItem + 1, 0, GetNumItems() - 1), true); break; case EMenuActionBinding::Confirm: break; case EMenuActionBinding::Back: onBack.Broadcast(); UEffectFunctionLibrary::PlaySoundEffect2D(GetWorld(), backAudioClass); break; } Super::NativeOnMenuAction(binding); } void USubMenu::NativeOnSelectionConfirmed(UMenuItemBase* item) { UEffectFunctionLibrary::PlaySoundEffect2D(GetWorld(), clickAudioClass); onItemSelectionConfirmed.Broadcast(m_items[m_selectedItem]); } UMenuItemBase* USubMenu::GetItem(int32 index) const { if(index >= m_items.Num() || index < 0) { GWWARNING(L"Item index out of range"); return nullptr; } return m_items[index]; } int32 USubMenu::GetNumItems() const { return m_items.Num(); } int32 USubMenu::GetSelectedItem() const { return m_selectedItem; } void USubMenu::SelectNewItemByIndex(int32 idx) { SelectNewItemByIndex(idx, false); } void USubMenu::SelectNewItemByIndex(int32 idx, bool controller) { if(idx >= m_items.Num() || idx < 0) { GWWARNING(L"Item index out of range"); return; } if(m_selectedItem != idx) { check(m_selectedItem < m_items.Num()); m_items[m_selectedItem]->NativeOnSelectionChanged(false, controller); m_items[idx]->NativeOnSelectionChanged(true, controller); m_selectedItem = idx; onItemSelected.Broadcast(m_items[m_selectedItem]); SetButtonHints(); UEffectFunctionLibrary::PlaySoundEffect2D(GetWorld(), selectionChangedAudioClass); } } void USubMenu::SelectNewItem(UMenuItemBase* item) { int32 idx = 0; if (m_items.Find(item, idx)) { SelectNewItemByIndex(idx); } } int32 USubMenu::GetItemIndex(UMenuItemBase* item) { int32 idx = 0; if (m_items.Find(item, idx)) return idx; return -1; } UMenuScreenBase* USubMenu::GetScreen() const { return m_screen; } void USubMenu::m_SetFocus(bool focus) { m_focus = focus; // Get Selected button UMenuItemBase* item = GetItem(GetSelectedItem()); if (item) { item->NativeOnSelectionChanged(true, false); } }