# pragma region License
/*
License ( OLC - 3 )
~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
Copyright 2024 Joshua Sigona < sigonasr2 @ gmail . com >
Redistribution and use in source and binary forms , with or without modification ,
are permitted provided that the following conditions are met :
1. Redistributions or derivations of source code must retain the above copyright
notice , this list of conditions and the following disclaimer .
2. Redistributions or derivative works in binary form must reproduce the above
copyright notice . This list of conditions and the following disclaimer must be
reproduced in the documentation and / or other materials provided with the distribution .
3. Neither the name of the copyright holder nor the names of its contributors may
be used to endorse or promote products derived from this software without specific
prior written permission .
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS " AND ANY
EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT
SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT ,
INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT LIMITED
TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR
BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN
CONTRACT , STRICT LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE .
Portions of this software are copyright © 2024 The FreeType
Project ( www . freetype . org ) . Please see LICENSE_FT . txt for more information .
All rights reserved .
*/
# pragma endregion
# include "Menu.h"
# include "DEFINES.h"
# include "MenuLabel.h"
# include "Key.h"
# include "InputDisplayComponent.h"
# include "olcPGEX_Gamepad.h"
using A = Attribute ;
INCLUDE_WINDOW_SIZE
INCLUDE_DATA
void Menu : : InitializeKeyboardInputWindow ( ) {
vf2d menuSize = { WINDOW_SIZE . x - 52.f , 176.f } ;
Menu * inputKeyboardWindow = CreateMenu ( INPUT_KEY_DISPLAY , CENTERED , menuSize ) ;
float inputWindowWidth = menuSize . x - 8 ;
inputKeyboardWindow - > ADD ( " Keyboard Mapping Label " , MenuLabel ) ( geom2d : : rect < float > { { 4 , 0 } , { menuSize . x - 8.f , 24.f } } , " Keyboard Mappings " , 2.f , ComponentAttr : : SHADOW | ComponentAttr : : BACKGROUND | ComponentAttr : : OUTLINE ) END ;
inputKeyboardWindow - > ADD ( " Menu Inputs Background " , MenuLabel ) ( geom2d : : rect < float > { { 4 , 32 } , { menuSize . x - 8 , 65.f } } , " " , 1.f , ComponentAttr : : BACKGROUND | ComponentAttr : : OUTLINE ) END ;
const int menuRowCount = DATA . GetProperty ( " Inputs.Menu Input Names " ) . GetValueCount ( ) % 2 = = 0 ? DATA . GetProperty ( " Inputs.Menu Input Names " ) . GetValueCount ( ) / 2 : DATA . GetProperty ( " Inputs.Menu Input Names " ) . GetValueCount ( ) / 2 + 1 ;
const int menuColCount = 2 ;
for ( int row = 0 ; row < menuRowCount ; row + + ) {
for ( int col = 0 ; col < menuColCount ; col + + ) {
if ( DATA . GetProperty ( " Inputs.Menu Input Names " ) . GetValueCount ( ) % 2 = = 1 & & col = = 1 & & row = = menuRowCount - 1 ) continue ; //We only continue on a blank space when we have an odd number of elements.
//Exclude the very last item because we only have 9 inputs to list.
int inputID = row * 2 + col ;
std : : string inputDisplayName = " Inputs.Menu Input Names " _s [ inputID ] ;
inputKeyboardWindow - > ADD ( std : : format ( " Input_{}_{} Background " , row , col ) , MenuLabel ) ( geom2d : : rect < float > { vf2d { 4 , 36 } + vf2d { inputWindowWidth / 2.f * col , row * 12.f } , { inputWindowWidth / 4.f , 11.f } } , inputDisplayName , 1.f , ComponentAttr : : FIT_TO_LABEL | ComponentAttr : : SHADOW ) END ;
auto inputChangeButton = inputKeyboardWindow - > ADD ( std : : format ( " Input_{}_{} Input Displayer " , row , col ) , InputDisplayComponent ) ( geom2d : : rect < float > { vf2d { 4 , 36 } + vf2d { inputWindowWidth / 2.f * col , row * 12.f } + vf2d { inputWindowWidth / 4.f , - 1.f } , vf2d { inputWindowWidth / 4.f , 11.f } } , * InputGroup : : menuNamesToInputGroups [ inputDisplayName ] , InputType : : KEY , [ ] ( MenuFuncData data ) {
Menu : : menus [ NEW_INPUT ] - > B ( A : : IS_KEYBOARD ) = DYNAMIC_POINTER_CAST < InputDisplayComponent > ( data . component ) - > GetType ( ) = = InputType : : KEY ;
std : : string keybindName = data . component . lock ( ) - > S ( A : : KEYBIND ) ;
Menu : : menus [ NEW_INPUT ] - > S ( A : : KEYBIND ) = keybindName ;
std : : string cancelButtonDisplayName = GenericKey : : keyLiteral [ { KEY , ESCAPE } ] . displayName ;
std : : string keyTypeName = " key " ;
if ( ! Menu : : menus [ NEW_INPUT ] - > B ( A : : IS_KEYBOARD ) ) { //Check if this is for a controller instead.
cancelButtonDisplayName = GenericKey : : keyLiteral [ { CONTROLLER , static_cast < int > ( GPButtons : : SELECT ) } ] . displayName ;
keyTypeName = " button " ;
}
Component < MenuLabel > ( NEW_INPUT , " New Keybind Label " ) - > SetLabel ( std : : format ( " Press a new {} for '{}' " , keyTypeName , keybindName ) ) ;
Menu : : OpenMenu ( NEW_INPUT ) ;
return true ;
} ) END ;
inputChangeButton - > S ( A : : KEYBIND ) = inputDisplayName ; //Store the keybind in this button to pass along information.
}
}
inputKeyboardWindow - > ADD ( " Controller Inputs Background " , MenuLabel ) ( geom2d : : rect < float > { { 4 , 100 } , { menuSize . x - 8 , 65.f } } , " " , 1.f , ComponentAttr : : BACKGROUND | ComponentAttr : : OUTLINE ) END ;
const int ingameControlsRowCount = DATA . GetProperty ( " Inputs.Gameplay Input Names " ) . GetValueCount ( ) % 2 = = 0 ? DATA . GetProperty ( " Inputs.Gameplay Input Names " ) . GetValueCount ( ) / 2 : DATA . GetProperty ( " Inputs.Gameplay Input Names " ) . GetValueCount ( ) / 2 + 1 ;
const int ingameControlsColCount = 2 ;
for ( int row = 0 ; row < ingameControlsRowCount ; row + + ) {
for ( int col = 0 ; col < ingameControlsColCount ; col + + ) {
if ( DATA . GetProperty ( " Inputs.Gameplay Input Names " ) . GetValueCount ( ) % 2 = = 1 & & col = = 1 & & row = = ingameControlsRowCount - 1 ) continue ; //We only continue on a blank space when we have an odd number of elements.
int inputID = row * 2 + col ;
std : : string inputDisplayName = " Inputs.Gameplay Input Names " _s [ inputID ] ;
inputKeyboardWindow - > ADD ( std : : format ( " GameplayInput_{}_{} Background " , row , col ) , MenuLabel ) ( geom2d : : rect < float > { vf2d { 4 , 104 } + vf2d { inputWindowWidth / 2.f * col , row * 12.f } , { inputWindowWidth / 4.f , 11.f } } , inputDisplayName , 1.f , ComponentAttr : : FIT_TO_LABEL | ComponentAttr : : SHADOW ) END ;
auto inputChangeButton = inputKeyboardWindow - > ADD ( std : : format ( " Input_{}_{} Gameplay Input Displayer " , row , col ) , InputDisplayComponent ) ( geom2d : : rect < float > { vf2d { 4 , 104 } + vf2d { inputWindowWidth / 2.f * col , row * 12.f } + vf2d { inputWindowWidth / 4.f , - 1.f } , vf2d { inputWindowWidth / 4.f , 11.f } } , * InputGroup : : menuNamesToInputGroups [ inputDisplayName ] , InputType : : KEY , [ ] ( MenuFuncData data ) {
Menu : : menus [ NEW_INPUT ] - > B ( A : : IS_KEYBOARD ) = DYNAMIC_POINTER_CAST < InputDisplayComponent > ( data . component ) - > GetType ( ) = = InputType : : KEY ;
std : : string keybindName = data . component . lock ( ) - > S ( A : : KEYBIND ) ;
Menu : : menus [ NEW_INPUT ] - > S ( A : : KEYBIND ) = keybindName ;
std : : string cancelButtonDisplayName = GenericKey : : keyLiteral [ { KEY , ESCAPE } ] . displayName ;
std : : string keyTypeName = " key " ;
if ( ! Menu : : menus [ NEW_INPUT ] - > B ( A : : IS_KEYBOARD ) ) { //Check if this is for a controller instead.
cancelButtonDisplayName = GenericKey : : keyLiteral [ { CONTROLLER , static_cast < int > ( GPButtons : : SELECT ) } ] . displayName ;
keyTypeName = " button " ;
}
Component < MenuLabel > ( NEW_INPUT , " New Keybind Label " ) - > SetLabel ( std : : format ( " Press a new {} for '{}' " , keyTypeName , keybindName ) ) ;
Menu : : OpenMenu ( NEW_INPUT ) ;
return true ;
} ) END ;
inputChangeButton - > S ( A : : KEYBIND ) = inputDisplayName ; //Store the keybind in this button to pass along information.
}
}
inputKeyboardWindow - > ADD ( " Confirm Button " , MenuComponent ) ( geom2d : : rect < float > { { menuSize . x / 2 - 48.f , 170.f } , { 96.f , 20.f } } , " Back " , [ ] ( MenuFuncData data ) {
Menu : : CloseMenu ( ) ;
return true ;
} ) END ;
inputKeyboardWindow - > SetupKeyboardNavigation (
[ ] ( MenuType type , Data & returnData ) { //On Open
returnData = " Input_0_0 Input Displayer " ;
} ,
{ //Button Key
{ game - > KEY_SCROLL , { " Navigate " , [ ] ( MenuType type ) { } } } ,
{ game - > KEY_BACK , { " Back " , [ ] ( MenuType type ) {
Menu : : CloseMenu ( ) ;
} } } ,
{ game - > KEY_CONFIRM , { " Select " , [ ] ( MenuType type ) { } } } ,
}
, { //Button Navigation Rules
{ " Input_0_0 Input Displayer " , {
. up = " Confirm Button " ,
. down = " Input_1_0 Input Displayer " ,
. left = " Input_0_1 Input Displayer " ,
. right = " Input_0_1 Input Displayer " ,
} } ,
{ " Input_0_1 Input Displayer " , {
. up = " Confirm Button " ,
. down = " Input_1_1 Input Displayer " ,
. left = " Input_0_0 Input Displayer " ,
. right = " Input_0_0 Input Displayer " ,
} } ,
{ " Input_1_0 Input Displayer " , {
. up = " Input_0_0 Input Displayer " ,
. down = " Input_2_0 Input Displayer " ,
. left = " Input_1_1 Input Displayer " ,
. right = " Input_1_1 Input Displayer " ,
} } ,
{ " Input_1_1 Input Displayer " , {
. up = " Input_0_1 Input Displayer " ,
. down = " Input_2_1 Input Displayer " ,
. left = " Input_1_0 Input Displayer " ,
. right = " Input_1_0 Input Displayer " ,
} } ,
{ " Input_2_0 Input Displayer " , {
. up = " Input_1_0 Input Displayer " ,
. down = " Input_3_0 Input Displayer " ,
. left = " Input_2_1 Input Displayer " ,
. right = " Input_2_1 Input Displayer " ,
} } ,
{ " Input_2_1 Input Displayer " , {
. up = " Input_1_1 Input Displayer " ,
. down = " Input_3_1 Input Displayer " ,
. left = " Input_2_0 Input Displayer " ,
. right = " Input_2_0 Input Displayer " ,
} } ,
{ " Input_3_0 Input Displayer " , {
. up = " Input_2_0 Input Displayer " ,
. down = " Input_4_0 Input Displayer " ,
. left = " Input_3_1 Input Displayer " ,
. right = " Input_3_1 Input Displayer " ,
} } ,
{ " Input_3_1 Input Displayer " , {
. up = " Input_2_1 Input Displayer " ,
. down = " Input_0_1 Gameplay Input Displayer " ,
. left = " Input_3_0 Input Displayer " ,
. right = " Input_3_0 Input Displayer " ,
} } ,
{ " Input_4_0 Input Displayer " , {
. up = " Input_3_0 Input Displayer " ,
. down = " Input_0_0 Gameplay Input Displayer " ,
. left = " Input_3_1 Input Displayer " ,
. right = " Input_3_1 Input Displayer " ,
} } ,
{ " Input_0_0 Gameplay Input Displayer " , {
. up = " Input_4_0 Input Displayer " ,
. down = " Input_1_0 Gameplay Input Displayer " ,
. left = " Input_0_1 Gameplay Input Displayer " ,
. right = " Input_0_1 Gameplay Input Displayer " ,
} } ,
{ " Input_0_1 Gameplay Input Displayer " , {
. up = " Input_3_1 Input Displayer " ,
. down = " Input_1_1 Gameplay Input Displayer " ,
. left = " Input_0_0 Gameplay Input Displayer " ,
. right = " Input_0_0 Gameplay Input Displayer " ,
} } ,
{ " Input_1_0 Gameplay Input Displayer " , {
. up = " Input_0_0 Gameplay Input Displayer " ,
. down = " Input_2_0 Gameplay Input Displayer " ,
. left = " Input_1_1 Gameplay Input Displayer " ,
. right = " Input_1_1 Gameplay Input Displayer " ,
} } ,
{ " Input_1_1 Gameplay Input Displayer " , {
. up = " Input_0_1 Gameplay Input Displayer " ,
. down = " Input_2_1 Gameplay Input Displayer " ,
. left = " Input_1_0 Gameplay Input Displayer " ,
. right = " Input_1_0 Gameplay Input Displayer " ,
} } ,
{ " Input_2_0 Gameplay Input Displayer " , {
. up = " Input_1_0 Gameplay Input Displayer " ,
. down = " Input_3_0 Gameplay Input Displayer " ,
. left = " Input_2_1 Gameplay Input Displayer " ,
. right = " Input_2_1 Gameplay Input Displayer " ,
} } ,
{ " Input_2_1 Gameplay Input Displayer " , {
. up = " Input_1_1 Gameplay Input Displayer " ,
. down = " Input_3_1 Gameplay Input Displayer " ,
. left = " Input_2_0 Gameplay Input Displayer " ,
. right = " Input_2_0 Gameplay Input Displayer " ,
} } ,
{ " Input_3_0 Gameplay Input Displayer " , {
. up = " Input_2_0 Gameplay Input Displayer " ,
. down = " Input_4_0 Gameplay Input Displayer " ,
. left = " Input_3_1 Gameplay Input Displayer " ,
. right = " Input_3_1 Gameplay Input Displayer " ,
} } ,
{ " Input_3_1 Gameplay Input Displayer " , {
. up = " Input_2_1 Gameplay Input Displayer " ,
. down = " Confirm Button " ,
. left = " Input_3_0 Gameplay Input Displayer " ,
. right = " Input_3_0 Gameplay Input Displayer " ,
} } ,
{ " Input_4_0 Gameplay Input Displayer " , {
. up = " Input_3_0 Gameplay Input Displayer " ,
. down = " Confirm Button " ,
. left = " Input_3_1 Gameplay Input Displayer " ,
. right = " Input_3_1 Gameplay Input Displayer " ,
} } ,
{ " Confirm Button " , {
. up = " Input_4_0 Gameplay Input Displayer " ,
. down = " Input_0_0 Input Displayer " ,
} } ,
} ) ;
}