Massively improved Config Key/Joy Mappings screen.

Warning is dismissable now, and cursor does not start in a position that will change a setting.
New special actions added:  ClearToDefault, ReloadFromDisk, SaveToDisk, SetListMode.  Exit is a special action.
Player is prompted to save when exiting screen instead of saving after every action.
Special actions fallback on Graphics/SMC action if they don't have their own.
Moved SMC overlay to Graphics/SMC warning.
Metrics for configuring input lock time, warning autodismiss time, lines visible, and NoSetListPrompt autodismiss time.
Header row added for cursor to start on.
ScreenMapControllers2 deleted as obsolete.
BitmapText:maxwidth changed to factor the zoom of the actor into the calculation.
This commit is contained in:
Kyzentun
2014-09-04 01:23:28 -06:00
parent e3f8d272c1
commit f2fdaa0cf5
17 changed files with 574 additions and 815 deletions
@@ -1,27 +0,0 @@
local waitTime = 7.5
local t = Def.ActorFrame {
InitCommand=cmd(x,SCREEN_CENTER_X;y,SCREEN_CENTER_Y);
OnCommand=cmd(queuecommand,"TweenOn";sleep,waitTime;queuecommand,"TweenOff");
}
t[#t+1] = Def.Quad {
InitCommand=cmd(zoomto,SCREEN_WIDTH,SCREEN_HEIGHT;diffuse,Color.Black);
TweenOnCommand=cmd(diffusealpha,1;linear,0.5;diffusealpha,0.8);
TweenOffCommand=cmd(linear,0.5;diffusealpha,0);
};
t[#t+1] = Def.ActorFrame {
LoadFont("Common Normal") .. {
Text=ScreenString("WarningHeader");
InitCommand=cmd(y,-70;diffuse,Color.Red);
TweenOnCommand=cmd(diffusealpha,0;zoomx,2;zoomy,0;sleep,0.5;smooth,0.25;zoom,1;diffusealpha,1);
TweenOffCommand=cmd(linear,0.5;diffusealpha,0);
};
LoadFont("Common Normal") .. {
Text=ScreenString("WarningText");
InitCommand=cmd(y,10;wrapwidthpixels,SCREEN_WIDTH-48);
TweenOnCommand=cmd(diffusealpha,0;sleep,0.5125;linear,0.125;diffusealpha,1);
TweenOffCommand=cmd(linear,0.5;diffusealpha,0);
};
};
return t
@@ -0,0 +1,16 @@
return LoadFont("Common Normal") .. {
InitCommand= cmd(x, SCREEN_CENTER_X; zoom, .75; shadowlength, 0; diffuse, color("#808080")),
OnCommand= function(self)
self:diffusealpha(0)
self:decelerate(0.5)
self:diffusealpha(1)
-- fancy effect: Look at the name (which is set by the screen) to set text
self:settext(
THEME:GetString("ScreenMapControllers", "Action" .. self:GetName()))
end,
OffCommand=cmd(stoptweening;accelerate,0.3;diffusealpha,0;queuecommand,"Hide");
HideCommand=cmd(visible,false);
GainFocusCommand=cmd(diffuseshift;effectcolor2,color("#808080");effectcolor1,color("#FFFFFF"));
LoseFocusCommand=cmd(stopeffect);
};
@@ -1,10 +0,0 @@
return LoadFont("Common Normal") .. {
Text="Exit";
InitCommand=cmd(x,SCREEN_CENTER_X;zoom,0.75;shadowlength,0;diffuse,color("#808080"));
OnCommand=cmd(diffusealpha,0;decelerate,0.5;diffusealpha,1);
OffCommand=cmd(stoptweening;accelerate,0.3;diffusealpha,0;queuecommand,"Hide");
HideCommand=cmd(visible,false);
GainFocusCommand=cmd(diffuseshift;effectcolor2,color("#808080");effectcolor1,color("#FFFFFF"));
LoseFocusCommand=cmd(stopeffect);
};
@@ -0,0 +1,17 @@
return Def.ActorFrame{
InitCommand=cmd(x,SCREEN_CENTER_X;y,SCREEN_CENTER_Y),
Def.Quad{
InitCommand=cmd(zoomto,SCREEN_WIDTH,SCREEN_HEIGHT;diffuse,Color.Black;diffusealpha,0),
TweenOnCommand=cmd(stoptweening;diffusealpha,1;linear,0.5;diffusealpha,0.8),
TweenOffCommand=cmd(stoptweening;linear,0.5;diffusealpha,0),
},
Def.ActorFrame{
Def.BitmapText{
Font="Common Normal",
Text=ScreenString("NoSetListPrompt"),
InitCommand=cmd(y,10;wrapwidthpixels,SCREEN_WIDTH-48;diffusealpha,0),
TweenOnCommand=cmd(stoptweening;diffusealpha,0;sleep,0.5125;linear,0.125;diffusealpha,1),
TweenOffCommand=cmd(stoptweening;linear,0.5;diffusealpha,0),
},
},
}
@@ -0,0 +1,24 @@
return Def.ActorFrame{
InitCommand=cmd(x,SCREEN_CENTER_X;y,SCREEN_CENTER_Y),
Def.Quad{
InitCommand=cmd(zoomto,SCREEN_WIDTH,SCREEN_HEIGHT;diffuse,Color.Black),
TweenOnCommand=cmd(diffusealpha,1;linear,0.5;diffusealpha,0.8),
TweenOffCommand=cmd(linear,0.5;diffusealpha,0),
},
Def.ActorFrame{
Def.BitmapText{
Font="Common Normal",
Text=ScreenString("WarningHeader"),
InitCommand=cmd(y,-80;diffuse,Color.Red),
TweenOnCommand=cmd(diffusealpha,0;zoomx,2;zoomy,0;sleep,0.5;smooth,0.25;zoom,1;diffusealpha,1),
TweenOffCommand=cmd(linear,0.5;diffusealpha,0),
},
Def.BitmapText{
Font="Common Normal",
Text=ScreenString("WarningText"),
InitCommand=cmd(y,10;wrapwidthpixels,SCREEN_WIDTH-48),
TweenOnCommand=cmd(diffusealpha,0;sleep,0.5125;linear,0.125;diffusealpha,1),
TweenOffCommand=cmd(linear,0.5;diffusealpha,0),
},
},
}
+11 -3
View File
@@ -1531,15 +1531,23 @@ Warning=Warning
BodyText=The StepMania program source code is licensed under a permissive open-source license.\n\nThe StepMania name and logos are protected by Trademark law.\n\nThe StepMania default theme SOUNDS ARE SEPARATELY OWNED BY THE AUTHORS. ALL OTHER THEME COMPONENTS ARE LICENSED UNDER THE STEPMANIA LICENSE.\n\nSee license.txt for details.
[ScreenMapControllers]
ActionClear=Clear To Default
ActionReload=Reload From Disk
ActionSave=Save To Disk
ActionSetList=Assign List
ActionExit=Exit
Default=Default
HeaderText=Map Controllers
InvalidButton=That key can not be mapped.
KeyName=Key Name
NoSetListPrompt=No entries in the list to set. Add entries to the list by hitting 'm' when the cursor is on them.
%s slots=%s slots
Primary=Primary
SavePrompt=Save settings before exiting?
Secondary=Secondary
WarningHeader=WARNING!
WarningText=Please ensure that you do not overwrite any important keymappings, such as:\n&MENULEFT; LEFT &MENURIGHT; RIGHT &MENUUP; UP &MENUDOWN; DOWN &START; START &BACK; BACK or &SELECT; SELECT. Do not apply keymappings that you do not know the function of or unmap important keys!
[ScreenMapControllers2]
Add Mapping=Add Mapping
[ScreenNetRoom]
Enter a description for the room:=Enter a description for the room:
Enter a password for the room (blank, no password):=Enter a password for the room (blank, no password):
+19 -2
View File
@@ -2855,13 +2855,28 @@ Fallback="ScreenOptionsServiceChild"
NextScreen="ScreenOptionsService"
HelpText=Screen.String("HelpTextMapControllers")
#
ScreenOnCommand=%function(self) MESSAGEMAN:Broadcast("KeyConfigRequestStall"); self:lockinput(5); end;
LockInputSecs=2.5
AutoDismissWarningSecs=2.5
LinesVisible=16
AutoDismissNoSetListPromptSecs=5
#
DevicesX=SCREEN_CENTER_X
DevicesY=SCREEN_TOP+24
DevicesOnCommand=zoom,0.75;draworder,5;strokecolor,color("0,0,0,1")
DevicesOffCommand=
#
HeaderP1S1Command=x,SCREEN_CENTER_X-270
HeaderP1S2Command=x,SCREEN_CENTER_X-195
HeaderP1S3Command=x,SCREEN_CENTER_X-120
HeaderP2S1Command=x,SCREEN_CENTER_X+120
HeaderP2S2Command=x,SCREEN_CENTER_X+195
HeaderP2S3Command=x,SCREEN_CENTER_X+270
#
headerCenterOnCommand=x,SCREEN_CENTER_X;y,-6;zoom,0.7;shadowlength,1;ztest,true
HeaderOnCommand=diffuse,color("#808080");shadowlength,0;zoom,0.75;maxwidth,130;
HeaderGainFocusCommand=diffuse,color("#808080");diffuseshift;effectcolor2,color("#808080");effectcolor1,color("#FFFFFF")
HeaderLoseFocusCommand=diffuse,color("#808080");stopeffect
#
ButtonsToMap=""
MappedToP1S1Command=x,SCREEN_CENTER_X-270
MappedToP1S2Command=x,SCREEN_CENTER_X-195
@@ -2870,11 +2885,13 @@ MappedToP2S1Command=x,SCREEN_CENTER_X+120
MappedToP2S2Command=x,SCREEN_CENTER_X+195
MappedToP2S3Command=x,SCREEN_CENTER_X+270
#
MappedToOnCommand=diffuse,color("#808080");shadowlength,0;maxwidth,150;zoom,0.75
MappedToOnCommand=diffuse,color("#808080");shadowlength,0;zoom,0.75;maxwidth,130
MappedToWaitingCommand=diffuse,color("#FF8080");pulse;effectperiod,0.5;effectmagnitude,0.8,1.3,0
MappedToMappedInputCommand=diffuse,color("#808080");diffuseshift;effectcolor2,color("#808080");effectcolor1,color("#FFFFFF")
MappedToGainFocusCommand=diffuse,color("#808080");diffuseshift;effectcolor2,color("#808080");effectcolor1,color("#FFFFFF")
MappedToLoseFocusCommand=diffuse,color("#808080");stopeffect
MappedToGainMarkCommand=textglowmode,'TextGlowMode_Inner';glow,color("#FF00007f")
MappedToLoseMarkCommand=textglowmode,'TextGlowMode_Inner';glow,color("#FF000000")
#
LineScrollerOnCommand=%function(self) self:draworder(-1); self:y(64) self:setsecondsperitem(0.1) self:SetTransformFromHeight(24) end
LineScrollerOffCommand=
+1
View File
@@ -1339,6 +1339,7 @@ ItemsLongRowSharedX=SCREEN_CENTER_X
[OptionRowMiniMenuContext]
[ScreenMapControllers]
LinesVisible=15
[ScreenTestInput]
+1 -1
View File
@@ -221,7 +221,7 @@ Actor *ActorUtil::LoadFromNode( const XNode* _pNode, Actor *pParentActor )
// sClass is invalid
RString sError = ssprintf( "%s: invalid Class \"%s\"",
ActorUtil::GetWhere(&node).c_str(), sClass.c_str() );
Dialog::OK( sError );
LuaHelpers::ReportScriptError(sError);
return new Actor; // Return a dummy object so that we don't crash in AutoActor later.
}
+4 -1
View File
@@ -6,7 +6,10 @@
void AutoActor::Unload()
{
delete m_pActor;
if(m_pActor != NULL)
{
delete m_pActor;
}
m_pActor=NULL;
}
+20 -27
View File
@@ -513,35 +513,28 @@ void BitmapText::UnSetDistortion()
void BitmapText::UpdateBaseZoom()
{
if( m_fMaxWidth == 0 )
{
this->SetBaseZoomX( 1 );
}
else
{
const float fWidth = GetUnzoomedWidth();
if( fWidth != 0 ) // don't divide by 0
{
// Never decrease the zoom.
const float fZoom = min( 1, m_fMaxWidth/fWidth );
this->SetBaseZoomX( fZoom );
}
// don't divide by 0
// Never apply a zoom greater than 1.
// Factor in the non-base zoom so that maxwidth will be in terms of theme
// pixels when zoom is used.
#define APPLY_DIMENSION_ZOOM(dimension_max, dimension_get, dimension_zoom_get, base_zoom_set) \
if(dimension_max == 0) \
{ \
base_zoom_set(1); \
} \
else \
{ \
const float dimension= dimension_get() / dimension_zoom_get(); \
if(dimension != 0) \
{ \
const float zoom= min(1, dimension_max / dimension); \
base_zoom_set(zoom); \
} \
}
if( m_fMaxHeight == 0 )
{
this->SetBaseZoomY( 1 );
}
else
{
const float fHeight = GetUnzoomedHeight();
if( fHeight != 0 ) // don't divide by 0
{
// Never decrease the zoom.
const float fZoom = min( 1, m_fMaxHeight/fHeight );
this->SetBaseZoomY( fZoom );
}
}
APPLY_DIMENSION_ZOOM(m_fMaxWidth, GetUnzoomedWidth, GetZoomX, SetBaseZoomX);
APPLY_DIMENSION_ZOOM(m_fMaxHeight, GetUnzoomedHeight, GetZoomY, SetBaseZoomY);
#undef APPLY_DIMENSION_ZOOM
}
bool BitmapText::StringWillUseAlternate( const RString& sText, const RString& sAlternateText ) const
+7
View File
@@ -654,6 +654,13 @@ void InputMapper::SaveMappingsToDisk()
m_mappings.WriteMappings( m_pInputScheme, SpecialFiles::KEYMAPS_PATH );
}
void InputMapper::ResetMappingsToDefault()
{
m_mappings.Clear();
UpdateTempDItoGI();
AddDefaultMappingsForCurrentGameIfUnmapped();
}
static LocalizedString CONNECTED ( "InputMapper", "Connected" );
static LocalizedString DISCONNECTED ( "InputMapper", "Disconnected" );
static LocalizedString AUTOMAPPING_ALL_JOYSTICKS ( "InputMapper", "Auto-mapping all joysticks." );
+1
View File
@@ -150,6 +150,7 @@ public:
void ReadMappingsFromDisk();
void SaveMappingsToDisk();
void ResetMappingsToDefault();
void ClearAllMappings();
+386 -73
View File
@@ -1,6 +1,7 @@
#include "global.h"
#include "ScreenMapControllers.h"
#include "ScreenManager.h"
#include "ScreenPrompt.h"
#include "RageLog.h"
#include "RageInput.h"
#include "InputMapper.h"
@@ -9,8 +10,10 @@
#include "InputEventPlus.h"
#include "LocalizedString.h"
AutoScreenMessage(SM_DoSaveAndExit);
#define BUTTONS_TO_MAP THEME->GetMetric ( m_sName, "ButtonsToMap" )
static LocalizedString INVALID_BUTTON ( "ScreenMapControllers", "InvalidButton" );
static LocalizedString SAVE_PROMPT("ScreenMapControllers", "SavePrompt");
#define MAPPED_TO_COMMAND(gc,slot) THEME->GetMetricA( m_sName, ssprintf("MappedToP%iS%iCommand", gc+1, slot+1) )
static const float g_fSecondsToWaitForInput = 0.05f;
@@ -22,10 +25,26 @@ REGISTER_SCREEN_CLASS( ScreenMapControllers );
ScreenMapControllers::ScreenMapControllers()
{
m_InSetListMode= false;
m_ChangeOccurred= false;
this->SubscribeToMessage( Message_AutoJoyMappingApplied );
}
ScreenMapControllers::~ScreenMapControllers()
{
for(size_t i= 0; i < m_Line.size(); ++i)
{
SAFE_DELETE(m_Line[i]);
}
}
static LocalizedString PLAYER_SLOTS( "ScreenMapControllers", "%s slots" );
static LocalizedString SLOT_NAMES[3]= {
LocalizedString("ScreenMapControllers", "Primary"),
LocalizedString("ScreenMapControllers", "Secondary"),
LocalizedString("ScreenMapControllers", "Default")
};
static LocalizedString KEYNAME("ScreenMapControllers", "KeyName");
void ScreenMapControllers::Init()
{
ScreenWithMenuElements::Init();
@@ -64,12 +83,11 @@ void ScreenMapControllers::Init()
}
}
int iRow = 0;
// header row
// slot names row
{
m_Line.push_back(new ActorFrame);
FOREACH_ENUM( GameController, c )
{
{
BitmapText &text = m_textLabel[c];
text.LoadFromFont( THEME->GetPathF(m_sName,"title") );
PlayerNumber pn = (PlayerNumber)c;
@@ -77,16 +95,40 @@ void ScreenMapControllers::Init()
RString sText = ssprintf(PLAYER_SLOTS.GetValue(), PlayerNumberToLocalizedString(pn).c_str());
text.SetText( sText );
ActorUtil::LoadAllCommands( text, m_sName );
m_Line[iRow].AddChild( &m_textLabel[c] );
m_Line.back()->AddChild( &m_textLabel[c] );
}
m_LineScroller.AddChild( &m_Line[iRow] );
iRow++;
m_LineScroller.AddChild(m_Line.back());
}
// header row
{
m_Line.push_back(new ActorFrame);
m_headerCenter.LoadFromFont(THEME->GetPathF(m_sName, "title"));
m_headerCenter.SetName("headerCenter");
m_headerCenter.SetText(KEYNAME);
ActorUtil::LoadAllCommands(m_headerCenter, m_sName);
m_Line.back()->AddChild(&m_headerCenter);
FOREACH_ENUM(GameController, c)
{
for(int s= 0; s < NUM_SHOWN_GAME_TO_DEVICE_SLOTS; ++s)
{
BitmapText& text= m_headerLabels[c][s];
text.LoadFromFont(THEME->GetPathF(m_sName, "title"));
PlayerNumber pn = (PlayerNumber)c;
text.SetName("Header");
text.SetText(SLOT_NAMES[s]);
text.RunCommands(THEME->GetMetricA(
m_sName, ssprintf("HeaderP%iS%iCommand", c+1, s+1)));
ActorUtil::LoadAllCommands(text, m_sName);
m_Line.back()->AddChild(&text);
}
}
m_LineScroller.AddChild(m_Line.back());
}
// normal rows
for( unsigned b=0; b<m_KeysToMap.size(); b++ )
{
m_Line.push_back(new ActorFrame);
KeyToMap *pKey = &m_KeysToMap[b];
{
@@ -96,7 +138,7 @@ void ScreenMapControllers::Init()
RString sText = GameButtonToLocalizedString( INPUTMAPPER->GetInputScheme(), pKey->m_GameButton );
pName->SetText( sText );
ActorUtil::LoadAllCommands( *pName, m_sName );
m_Line[iRow].AddChild( pName );
m_Line.back()->AddChild( pName );
}
{
BitmapText *pSecondary = new BitmapText;
@@ -108,11 +150,11 @@ void ScreenMapControllers::Init()
sText = GameButtonToLocalizedString( INPUTMAPPER->GetInputScheme(), mb );
ActorUtil::LoadAllCommands( *pSecondary, m_sName );
pSecondary->SetText( sText );
m_Line[iRow].AddChild( pSecondary );
m_Line.back()->AddChild( pSecondary );
}
FOREACH_ENUM( GameController, c )
{
{
for( int s=0; s<NUM_SHOWN_GAME_TO_DEVICE_SLOTS; s++ )
{
pKey->m_textMappedTo[c][s] = new BitmapText;
@@ -120,34 +162,50 @@ void ScreenMapControllers::Init()
pKey->m_textMappedTo[c][s]->LoadFromFont( THEME->GetPathF(m_sName,"entry") );
pKey->m_textMappedTo[c][s]->RunCommands( MAPPED_TO_COMMAND(c,s) );
ActorUtil::LoadAllCommands( *pKey->m_textMappedTo[c][s], m_sName );
m_Line[iRow].AddChild( pKey->m_textMappedTo[c][s] );
m_Line.back()->AddChild( pKey->m_textMappedTo[c][s] );
}
}
m_Line[iRow].DeleteChildrenWhenDone();
m_Line[iRow].SetName( "Line" );
ActorUtil::LoadAllCommands( m_Line[iRow], m_sName );
m_LineScroller.AddChild( &m_Line[iRow] );
iRow++;
}
// exit row
{
m_sprExit.Load( THEME->GetPathG(m_sName,"exit") );
m_sprExit->SetName( "Exit" );
ActorUtil::LoadAllCommands( *m_sprExit, m_sName );
m_Line[iRow].AddChild( m_sprExit );
m_LineScroller.AddChild( &m_Line[iRow] );
iRow++;
m_Line.back()->DeleteChildrenWhenDone();
m_Line.back()->SetName( "Line" );
ActorUtil::LoadAllCommands(m_Line.back(), m_sName);
m_LineScroller.AddChild(m_Line.back());
}
#define ADD_ACTION(index, a, b, c, d, e) \
m_Line.push_back(new ActorFrame); \
m_Actions[index].Load(a, b, c, d, e);
m_Actions.resize(5);
ADD_ACTION(0, m_sName, "Clear", &ScreenMapControllers::ClearToDefault,
m_Line.back(), &m_LineScroller);
ADD_ACTION(1, m_sName, "Reload", &ScreenMapControllers::ReloadFromDisk,
m_Line.back(), &m_LineScroller);
ADD_ACTION(2, m_sName, "Save", &ScreenMapControllers::SaveToDisk,
m_Line.back(), &m_LineScroller);
ADD_ACTION(3, m_sName, "SetList", &ScreenMapControllers::SetListMode,
m_Line.back(), &m_LineScroller);
ADD_ACTION(4, m_sName, "Exit", &ScreenMapControllers::ExitAction,
m_Line.back(), &m_LineScroller);
#undef ADD_ACTION
m_MaxDestItem= (1 + m_KeysToMap.size() + m_Actions.size()) -
THEME->GetMetricI("ScreenMapControllers", "LinesVisible");
m_LineScroller.SetName( "LineScroller" );
ActorUtil::LoadAllCommands( m_LineScroller, m_sName );
m_LineScroller.SetNumItemsToDraw( (float) m_LineScroller.GetNumChildren()*2 );
m_LineScroller.Load2();
this->AddChild( &m_LineScroller );
m_NoSetListPrompt.Load(THEME->GetPathG(m_sName, "nosetlistprompt"));
m_NoSetListPrompt->SetName("NoSetListPrompt");
this->AddChild(m_NoSetListPrompt);
m_sprWarning.Load(THEME->GetPathG(m_sName, "warning"));
m_sprWarning->SetName("Warning");
m_sprWarning->SetDrawOrder(DRAW_ORDER_TRANSITIONS);
this->AddChild(m_sprWarning);
LOAD_ALL_COMMANDS(m_sprWarning);
}
void ScreenMapControllers::BeginScreen()
@@ -162,6 +220,10 @@ void ScreenMapControllers::BeginScreen()
Refresh();
AfterChangeFocus();
m_fLockInputSecs= THEME->GetMetricF(m_sName, "LockInputSecs");
m_AutoDismissWarningSecs= THEME->GetMetricF(m_sName, "AutoDismissWarningSecs");
m_AutoDismissNoSetListPromptSecs= 0.0f;
m_sprWarning->PlayCommand("TweenOn");
}
@@ -169,34 +231,64 @@ void ScreenMapControllers::Update( float fDeltaTime )
{
ScreenWithMenuElements::Update( fDeltaTime );
if(m_fLockInputSecs <= 0.0f)
{
bool was_above= m_AutoDismissWarningSecs > 0.0f;
m_AutoDismissWarningSecs-= fDeltaTime;
if(was_above && m_AutoDismissWarningSecs <= 0.0f)
{
DismissWarning();
}
}
if(m_AutoDismissNoSetListPromptSecs > 0.0f)
{
m_AutoDismissNoSetListPromptSecs-= fDeltaTime;
if(m_AutoDismissNoSetListPromptSecs <= 0.0f)
{
m_NoSetListPrompt->PlayCommand("TweenOff");
}
}
//
// Update devices text
//
m_textDevices.SetText( INPUTMAN->GetDisplayDevicesString() );
if( !m_WaitingForPress.IsZero() && m_DeviceIToMap.IsValid() ) // we're going to map an input
{
if( m_WaitingForPress.PeekDeltaTime() < g_fSecondsToWaitForInput )
return; /* keep waiting */
m_WaitingForPress.SetZero();
ASSERT( m_iCurButton < (int) m_KeysToMap.size() );
const KeyToMap *pKey = &m_KeysToMap[m_iCurButton];
ASSERT(CursorOnKey());
const KeyToMap *pKey = &m_KeysToMap[CurKeyIndex()];
GameInput curGameI( (GameController)m_iCurController, pKey->m_GameButton );
INPUTMAPPER->SetInputMap( m_DeviceIToMap, curGameI, m_iCurSlot );
INPUTMAPPER->AddDefaultMappingsForCurrentGameIfUnmapped();
// commit to disk after each change
INPUTMAPPER->SaveMappingsToDisk();
Refresh();
m_ChangeOccurred= true;
BitmapText *pText = pKey->m_textMappedTo[m_iCurController][m_iCurSlot];
pText->PlayCommand( "MappedInput" );
pText->PlayCommand("MappedInput");
if(m_InSetListMode)
{
pText->PlayCommand("LoseMark");
++m_SetListCurrent;
if(m_SetListCurrent == m_SetList.end())
{
m_InSetListMode= false;
m_SetList.clear();
}
else
{
BeforeChangeFocus();
SetCursorFromSetListCurrent();
AfterChangeFocus();
StartWaitingForPress();
}
}
Refresh();
SCREENMAN->PlayStartSound();
}
}
@@ -230,16 +322,47 @@ static bool IsAxis( const DeviceInput& DeviceI )
bool ScreenMapControllers::Input( const InputEventPlus &input )
{
if( m_fLockInputSecs > 0 )
if(m_fLockInputSecs > 0.0f)
{
return false;
}
if(m_AutoDismissWarningSecs > 0.0f)
{
if(input.type == IET_FIRST_PRESS &&
input.DeviceI.device == DEVICE_KEYBOARD &&
input.DeviceI.button == KEY_ENTER)
{
m_AutoDismissWarningSecs = 0.0f;
DismissWarning();
}
return false;
}
if(m_AutoDismissNoSetListPromptSecs > 0.0f)
{
if(input.type == IET_FIRST_PRESS &&
input.DeviceI.device == DEVICE_KEYBOARD &&
input.DeviceI.button == KEY_ENTER)
{
m_AutoDismissNoSetListPromptSecs = 0.0f;
m_NoSetListPrompt->PlayCommand("TweenOff");
}
return false;
}
if( input.type != IET_FIRST_PRESS && input.type != IET_REPEAT )
{
return false; // ignore
}
if( IsTransitioning() )
{
return false; // ignore
}
LOG->Trace( "ScreenMapControllers::Input(): device: %d, button: %d",
input.DeviceI.device, input.DeviceI.button );
// Whoever wants it can uncomment this log spew, I don't think it's necessary. -Kyz
// LOG->Trace( "ScreenMapControllers::Input(): device: %d, button: %d",
// input.DeviceI.device, input.DeviceI.button );
int button = input.DeviceI.button;
bool bHandled = false;
@@ -290,11 +413,12 @@ bool ScreenMapControllers::Input( const InputEventPlus &input )
case KEY_DEL:
case KEY_SPACE:
case KEY_BACK: // Clear the selected input mapping.
if( m_iCurButton == (int) m_KeysToMap.size() )
break; // on exit
if(!CursorOnKey())
{
const KeyToMap *pKey = &m_KeysToMap[m_iCurButton];
break;
}
{
const KeyToMap *pKey = &m_KeysToMap[CurKeyIndex()];
GameInput curGameI( (GameController)m_iCurController, pKey->m_GameButton );
if( !INPUTMAPPER->ClearFromInputMap(curGameI, m_iCurSlot) )
break;
@@ -302,17 +426,18 @@ bool ScreenMapControllers::Input( const InputEventPlus &input )
INPUTMAPPER->AddDefaultMappingsForCurrentGameIfUnmapped();
m_soundDelete.Play();
// commit to disk after each change
INPUTMAPPER->SaveMappingsToDisk();
bHandled = true;
}
break;
case KEY_LEFT: // Move the selection left, wrapping up.
if( m_iCurButton == (int) m_KeysToMap.size() )
break; // on exit
if(CursorOnAction())
{
break;
}
if( m_iCurSlot == 0 && m_iCurController == 0 )
{
break; // can't go left any more
}
BeforeChangeFocus();
m_iCurSlot--;
if( m_iCurSlot < 0 )
@@ -325,10 +450,14 @@ bool ScreenMapControllers::Input( const InputEventPlus &input )
bHandled = true;
break;
case KEY_RIGHT: // Move the selection right, wrapping down.
if( m_iCurButton == (int) m_KeysToMap.size() )
break; // on exit
if(CursorOnAction())
{
break;
}
if( m_iCurSlot == NUM_CHANGABLE_SLOTS-1 && m_iCurController == NUM_GameController-1 )
{
break; // can't go right any more
}
BeforeChangeFocus();
m_iCurSlot++;
if( m_iCurSlot > NUM_CHANGABLE_SLOTS-1 )
@@ -341,8 +470,10 @@ bool ScreenMapControllers::Input( const InputEventPlus &input )
bHandled = true;
break;
case KEY_UP: // Move the selection up.
if( m_iCurButton == 0 )
break; // can't go up any more
if(!CursorCanGoUp())
{
break;
}
BeforeChangeFocus();
m_iCurButton--;
AfterChangeFocus();
@@ -350,8 +481,10 @@ bool ScreenMapControllers::Input( const InputEventPlus &input )
bHandled = true;
break;
case KEY_DOWN: // Move the selection down.
if( m_iCurButton == (int) m_KeysToMap.size() )
break; // can't go down any more
if(!CursorCanGoDown())
{
break;
}
BeforeChangeFocus();
m_iCurButton++;
AfterChangeFocus();
@@ -359,35 +492,50 @@ bool ScreenMapControllers::Input( const InputEventPlus &input )
bHandled = true;
break;
case KEY_ESC: // Quit the screen.
SCREENMAN->PlayStartSound();
StartTransitioningScreen( SM_GoToNextScreen );
ExitAction();
bHandled = true;
break;
case KEY_Cm:
if(CursorOnKey())
{
SetListEntry to_add(SetListEntry(CurKeyIndex(), m_iCurController, m_iCurSlot));
set<SetListEntry>::iterator found= m_SetList.find(to_add);
if(found == m_SetList.end())
{
m_SetList.insert(to_add);
GetActorWithFocus()->PlayCommand("GainMark");
}
else
{
m_SetList.erase(found);
GetActorWithFocus()->PlayCommand("LoseMark");
}
}
break;
case KEY_ENTER: // Change the selection.
case KEY_KP_ENTER:
if( m_iCurButton == (int) m_KeysToMap.size() )
bHandled = true;
if(CursorOnAction())
{
(this->*m_Actions[CurActionIndex()].m_action)();
SCREENMAN->PlayStartSound();
StartTransitioningScreen( SM_GoToNextScreen );
break;
}
if(CursorOnHeader())
{
const KeyToMap *pKey = &m_KeysToMap[m_iCurButton];
BitmapText *pText = pKey->m_textMappedTo[m_iCurController][m_iCurSlot];
pText->PlayCommand( "Waiting" );
break;
}
m_WaitingForPress.Touch();
m_DeviceIToMap.MakeInvalid();
StartWaitingForPress();
SCREENMAN->PlayStartSound();
bHandled = true;
break;
}
}
// ScreenWithMenuElements::Input( input ); // default handler
LOG->Trace( "m_iCurSlot: %d m_iCurController: %d m_iCurButton: %d", m_iCurSlot, m_iCurController, m_iCurButton );
// This trace is also useless log spew. Create a preference or something
// configurable if you disagree. -Kyz
// LOG->Trace( "m_iCurSlot: %d m_iCurController: %d m_iCurButton: %d", m_iCurSlot, m_iCurController, m_iCurButton );
Refresh();
return bHandled;
@@ -395,10 +543,16 @@ bool ScreenMapControllers::Input( const InputEventPlus &input )
Actor *ScreenMapControllers::GetActorWithFocus()
{
if( m_iCurButton == (int) m_KeysToMap.size() )
return m_sprExit;
if(CursorOnAction())
{
return m_Actions[CurActionIndex()].m_actor;
}
if(CursorOnHeader())
{
return &(m_headerLabels[m_iCurController][m_iCurSlot]);
}
const KeyToMap *pKey = &m_KeysToMap[m_iCurButton];
const KeyToMap *pKey = &m_KeysToMap[CurKeyIndex()];
return pKey->m_textMappedTo[m_iCurController][m_iCurSlot];
}
@@ -434,7 +588,97 @@ void ScreenMapControllers::Refresh()
}
}
m_LineScroller.SetDestinationItem( (float) m_iCurButton );
m_LineScroller.SetDestinationItem(
static_cast<float>(min(m_iCurButton, m_MaxDestItem)));
}
void ScreenMapControllers::DismissWarning()
{
m_sprWarning->PlayCommand("TweenOff");
}
bool ScreenMapControllers::CursorOnAction()
{
// We have a header row, the rows for the keys, and the action rows.
// So every row after m_KeysToMap.size is an action row.
return m_iCurButton >= static_cast<int>(m_KeysToMap.size()+1);
}
bool ScreenMapControllers::CursorOnHeader()
{
// We have a header row before all others.
// So the header is at 0.
return m_iCurButton == 0;
}
bool ScreenMapControllers::CursorOnKey()
{
return !(CursorOnHeader() || CursorOnAction());
}
bool ScreenMapControllers::CursorCanGoUp()
{
return m_iCurButton > 0;
}
bool ScreenMapControllers::CursorCanGoDown()
{
return m_iCurButton < m_KeysToMap.size() + m_Actions.size();
}
int ScreenMapControllers::CurKeyIndex()
{
// The header row is at 0, so subtract 1 from m_iCurButton.
return m_iCurButton - 1;
}
int ScreenMapControllers::CurActionIndex()
{
// Subtract the header row and the keys.
return m_iCurButton - 1 - m_KeysToMap.size();
}
void ScreenMapControllers::SetCursorFromSetListCurrent()
{
m_iCurButton= m_SetListCurrent->m_button + 1;
m_iCurController= m_SetListCurrent->m_controller;
m_iCurSlot= m_SetListCurrent->m_slot;
}
void ScreenMapControllers::StartWaitingForPress()
{
const KeyToMap *pKey = &m_KeysToMap[CurKeyIndex()];
BitmapText *pText = pKey->m_textMappedTo[m_iCurController][m_iCurSlot];
pText->PlayCommand( "Waiting" );
m_WaitingForPress.Touch();
m_DeviceIToMap.MakeInvalid();
}
void ScreenMapControllers::HandleScreenMessage(const ScreenMessage SM)
{
if(SM == SM_DoSaveAndExit)
{
switch(ScreenPrompt::s_LastAnswer)
{
DEFAULT_FAIL(ScreenPrompt::s_LastAnswer);
case ANSWER_YES:
SaveToDisk();
SCREENMAN->PlayStartSound();
StartTransitioningScreen(SM_GoToNextScreen);
break;
case ANSWER_NO:
ReloadFromDisk();
SCREENMAN->PlayStartSound();
StartTransitioningScreen(SM_GoToNextScreen);
break;
case ANSWER_CANCEL:
break;
}
}
else
{
ScreenWithMenuElements::HandleScreenMessage(SM);
}
}
void ScreenMapControllers::HandleMessage( const Message &msg )
@@ -447,9 +691,78 @@ void ScreenMapControllers::HandleMessage( const Message &msg )
ScreenWithMenuElements::HandleMessage( msg );
}
void ScreenMapControllers::ClearToDefault()
{
INPUTMAPPER->ResetMappingsToDefault();
}
void ScreenMapControllers::ReloadFromDisk()
{
INPUTMAPPER->ReadMappingsFromDisk();
}
void ScreenMapControllers::SaveToDisk()
{
INPUTMAPPER->SaveMappingsToDisk();
m_ChangeOccurred= false;
}
void ScreenMapControllers::SetListMode()
{
if(m_SetList.size() < 1)
{
m_NoSetListPrompt->PlayCommand("TweenOn");
m_AutoDismissNoSetListPromptSecs= THEME->GetMetricF(m_sName, "AutoDismissNoSetListPromptSecs");
}
else
{
m_SetListCurrent= m_SetList.begin();
m_InSetListMode= true;
BeforeChangeFocus();
SetCursorFromSetListCurrent();
AfterChangeFocus();
StartWaitingForPress();
}
}
void ScreenMapControllers::ExitAction()
{
if(m_ChangeOccurred)
{
ScreenPrompt::Prompt(SM_DoSaveAndExit, SAVE_PROMPT, PROMPT_YES_NO_CANCEL,
ANSWER_YES);
}
else
{
SCREENMAN->PlayStartSound();
StartTransitioningScreen(SM_GoToNextScreen);
}
}
void ScreenMapControllers::ActionRow::Load(RString const& scr_name,
RString const& name, ScreenMapControllers::action_fun_t action,
ActorFrame* line, ActorScroller* scroller)
{
m_action= action;
RString lower_name= name;
lower_name.MakeLower();
// Make the specific actor optional, use a fallback if it doesn't exist.
RString path= THEME->GetPathG(scr_name, lower_name, true);
if(path.empty())
{
path= THEME->GetPathG(scr_name, "action");
}
m_actor.Load(path);
m_actor->SetName(name);
ActorUtil::LoadAllCommands(*m_actor, scr_name);
line->AddChild(m_actor);
scroller->AddChild(line);
}
/*
* (c) 2001-2005 Chris Danford, Glenn Maynard
* 2014 Eric Reese
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
+67 -3
View File
@@ -13,23 +13,38 @@ class ScreenMapControllers : public ScreenWithMenuElements
{
public:
ScreenMapControllers();
~ScreenMapControllers();
virtual void Init();
virtual void BeginScreen();
virtual void Update( float fDeltaTime );
virtual bool Input( const InputEventPlus &input );
virtual void HandleMessage( const Message &msg );
virtual void HandleScreenMessage( const ScreenMessage SM );
private:
virtual void HandleMessage( const Message &msg );
Actor *GetActorWithFocus();
void BeforeChangeFocus();
void AfterChangeFocus();
void Refresh();
void DismissWarning();
bool CursorOnAction();
bool CursorOnHeader();
bool CursorOnKey();
bool CursorCanGoUp();
bool CursorCanGoDown();
int CurKeyIndex();
int CurActionIndex();
void SetCursorFromSetListCurrent();
void StartWaitingForPress();
int m_iCurController;
int m_iCurButton;
int m_iCurSlot;
int m_MaxDestItem;
bool m_ChangeOccurred;
RageTimer m_WaitingForPress;
DeviceInput m_DeviceIToMap;
@@ -46,10 +61,58 @@ private:
BitmapText m_textDevices;
BitmapText m_textLabel[NUM_GameController];
BitmapText m_headerCenter;
BitmapText m_headerLabels[NUM_GameController][NUM_SHOWN_GAME_TO_DEVICE_SLOTS];
AutoActor m_sprExit;
float m_AutoDismissWarningSecs;
AutoActor m_sprWarning;
ActorFrame m_Line[NUM_GameButton+2]; // label, normal lines, exit
float m_AutoDismissNoSetListPromptSecs;
AutoActor m_NoSetListPrompt;
struct SetListEntry
{
int m_button;
int m_controller;
int m_slot;
SetListEntry(int b, int c, int s)
:m_button(b), m_controller(c), m_slot(s) {}
bool operator<(SetListEntry const& rhs) const
{
if(m_controller != rhs.m_controller)
{
return m_controller < rhs.m_controller;
}
if(m_button != rhs.m_button)
{
return m_button < rhs.m_button;
}
return m_slot < rhs.m_slot;
}
};
set<SetListEntry> m_SetList;
set<SetListEntry>::iterator m_SetListCurrent;
bool m_InSetListMode;
typedef void (ScreenMapControllers::* action_fun_t)();
struct ActionRow
{
RString m_name;
AutoActor m_actor;
action_fun_t m_action;
void Load(RString const& scr_name, RString const& name,
ScreenMapControllers::action_fun_t action, ActorFrame* line,
ActorScroller* scroller);
};
void ClearToDefault();
void ReloadFromDisk();
void SaveToDisk();
void SetListMode();
void ExitAction();
vector<ActionRow> m_Actions;
vector<ActorFrame*> m_Line;
ActorScroller m_LineScroller;
RageSound m_soundChange;
@@ -60,6 +123,7 @@ private:
/*
* (c) 2001-2004 Chris Danford
* 2014 Eric Reese
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
-532
View File
@@ -1,532 +0,0 @@
#include "global.h"
#include "ScreenMapControllers2.h"
#include "ScreenManager.h"
#include "RageLog.h"
#include "GameState.h"
#include "RageInput.h"
#include "InputMapper.h"
#include "ThemeManager.h"
#include "ScreenDimensions.h"
#include "InputEventPlus.h"
#include "LocalizedString.h"
#include "Foreach.h"
#include "LuaBinding.h"
static const float g_fSecondsToWaitForInput = 0.05f;
static const char *MapControlsStateNames[] = {
"SelectingButton",
"EditingMappings"
};
XToString( MapControlsState );
LuaXType( MapControlsState );
REGISTER_SCREEN_CLASS( ScreenMapControllers2 );
ScreenMapControllers2::ScreenMapControllers2()
{
this->SubscribeToMessage( Message_AutoJoyMappingApplied );
m_MapControlsState = MCS_Button;
m_EditingButton = GAME_BUTTON_MENULEFT;
ZERO( m_iMappingChoice );
ZERO( m_iNumMappingRows );
}
static LocalizedString ADD_MAPPING( "ScreenMapControllers2", "Add Mapping" );
void ScreenMapControllers2::Init()
{
ScreenWithMenuElements::Init();
// load sounds
m_soundChange.Load( THEME->GetPathS(m_sName,"change"), true );
m_soundDelete.Load( THEME->GetPathS(m_sName,"delete"), true );
// set devices text
m_textDevices.LoadFromFont( THEME->GetPathF(m_sName,"devices") );
m_textDevices.SetName( "Devices" );
LOAD_ALL_COMMANDS_AND_SET_XY( m_textDevices );
this->AddChild( &m_textDevices );
// button input scroller
WRAP_INPUT_SCROLLER.Load( m_sName, "WrapInputScroller" );
LOOP_INPUT_SCROLLER.Load( m_sName, "LoopInputScroller" );
INPUT_SCROLLER_SECONDS_PER_ITEM.Load( m_sName, "InputScrollerSecondsPerItem" );
INPUT_SCROLLER_NUM_ITEMS_TO_DRAW.Load( m_sName, "InputScrollerNumItemsToDraw" );
INPUT_SCROLLER_TRANSFORM.Load( m_sName, "InputScrollerTransform" );
INPUT_SCROLLER_SUBDIVISIONS.Load( m_sName, "InputScrollerSubdivisions" );
// map all buttons for this game. (todo: re-add BUTTONS_TO_MAP support?)
FOREACH_GameButtonInScheme( INPUTMAPPER->GetInputScheme(), gb )
{
KeyToMap k;
k.m_GameButton = gb;
m_KeysToMap.push_back( k );
}
// input button names
int iRow = 0;
for( unsigned b=0; b<m_KeysToMap.size(); b++ )
{
KeyToMap *pKey = &m_KeysToMap[b];
{
BitmapText *pName = new BitmapText;
pName->SetName( "ButtonName" );
pName->LoadFromFont( THEME->GetPathF(m_sName,"ButtonName") );
RString sText = GameButtonToLocalizedString( INPUTMAPPER->GetInputScheme(), pKey->m_GameButton );
pName->SetText( sText );
ActorUtil::LoadAllCommands( *pName, m_sName );
pName->PlayCommand( b == (unsigned)m_iInputChoice ? "GainFocus" : "LoseFocus" );
m_InputLine[iRow].AddChild( pName );
}
m_InputLine[iRow].DeleteChildrenWhenDone();
m_InputLine[iRow].SetName( "InputLine" );
ActorUtil::LoadAllCommands( m_InputLine[iRow], m_sName );
m_InputScroller.AddChild( &m_InputLine[iRow] );
iRow++;
}
m_InputScroller.SetName( "InputScroller" );
LOAD_ALL_COMMANDS_AND_SET_XY( m_InputScroller );
m_InputScroller.SetLoop( LOOP_INPUT_SCROLLER );
m_InputScroller.SetNumItemsToDraw( INPUT_SCROLLER_NUM_ITEMS_TO_DRAW );
m_InputScroller.Load2();
m_InputScroller.SetTransformFromReference( INPUT_SCROLLER_TRANSFORM );
m_InputScroller.SetSecondsPerItem( INPUT_SCROLLER_SECONDS_PER_ITEM );
m_InputScroller.SetNumSubdivisions( INPUT_SCROLLER_SUBDIVISIONS );
this->AddChild( &m_InputScroller );
// set player scrollers:
vector<PlayerNumber> vpns;
FOREACH_PlayerNumber( p )
vpns.push_back( p );
// per-player mappings
WRAP_MAPPING_SCROLLER.Load( m_sName, "WrapMappingScroller" );
LOOP_MAPPING_SCROLLER.Load( m_sName, "LoopMappingScroller" );
MAPPING_SCROLLER_SECONDS_PER_ITEM.Load( m_sName, "MappingScrollerSecondsPerItem" );
MAPPING_SCROLLER_NUM_ITEMS_TO_DRAW.Load( m_sName, "MappingScrollerNumItemsToDraw" );
MAPPING_SCROLLER_TRANSFORM.Load( m_sName, "MappingScrollerTransform" );
MAPPING_SCROLLER_SUBDIVISIONS.Load( m_sName, "MappingScrollerSubdivisions" );
FOREACH( PlayerNumber, vpns, p )
{
// mapping scroller
m_MappingScroller[*p].SetLoop( LOOP_MAPPING_SCROLLER );
m_MappingScroller[*p].SetNumItemsToDraw( MAPPING_SCROLLER_NUM_ITEMS_TO_DRAW );
m_MappingScroller[*p].Load2();
m_MappingScroller[*p].SetTransformFromReference( MAPPING_SCROLLER_TRANSFORM );
m_MappingScroller[*p].SetSecondsPerItem( MAPPING_SCROLLER_SECONDS_PER_ITEM );
m_MappingScroller[*p].SetNumSubdivisions( MAPPING_SCROLLER_SUBDIVISIONS );
m_MappingScroller[*p].SetName( "MappingScroller"+ssprintf("P%d",(*p)+1) );
LOAD_ALL_COMMANDS_AND_SET_XY( m_MappingScroller[*p] );
this->AddChild( &m_MappingScroller[*p] );
}
}
void ScreenMapControllers2::BeginScreen()
{
m_iInputChoice = 0;
m_ActivePlayerMapping = PLAYER_1;
ScreenWithMenuElements::BeginScreen();
m_WaitingForPress.SetZero();
Refresh();
}
void ScreenMapControllers2::Update( float fDeltaTime )
{
ScreenWithMenuElements::Update( fDeltaTime );
// Update devices text
m_textDevices.SetText( INPUTMAN->GetDisplayDevicesString() );
if( !m_WaitingForPress.IsZero() && m_DeviceIToMap.IsValid() )
{
// we're going to map an input
if( m_WaitingForPress.PeekDeltaTime() < g_fSecondsToWaitForInput )
return; // keep waiting
m_WaitingForPress.SetZero();
/* do stuff here */
//ASSERT( m_iCurButton < (int) m_KeysToMap.size() );
//const KeyToMap *pKey = &m_KeysToMap[m_iCurButton];
//GameInput curGameI( (GameController)m_iCurController, pKey->m_GameButton );
//INPUTMAPPER->SetInputMap( m_DeviceIToMap, curGameI, m_iCurSlot );
//INPUTMAPPER->AddDefaultMappingsForCurrentGameIfUnmapped();
// commit to disk after each change
//INPUTMAPPER->SaveMappingsToDisk();
Refresh();
/*
BitmapText *pText = pKey->m_textMappedTo[m_iCurController][m_iCurSlot];
pText->PlayCommand( "MappedInput" );
*/
SCREENMAN->PlayStartSound();
}
}
/* Note that this isn't necessarily correct. For example, JOY_LEFT might
* actually be a D-pad and not an axis. All this is actually doing is giving
* priority to some inputs over others; this function is unsuitable for other use. */
static bool IsAxis( const DeviceInput& DeviceI )
{
if( !DeviceI.IsJoystick() )
return false;
static int axes[] =
{
JOY_LEFT, JOY_RIGHT, JOY_UP, JOY_DOWN,
JOY_LEFT_2, JOY_RIGHT_2, JOY_UP_2, JOY_DOWN_2,
JOY_Z_UP, JOY_Z_DOWN,
JOY_ROT_UP, JOY_ROT_DOWN, JOY_ROT_LEFT, JOY_ROT_RIGHT, JOY_ROT_Z_UP, JOY_ROT_Z_DOWN,
JOY_HAT_LEFT, JOY_HAT_RIGHT, JOY_HAT_UP, JOY_HAT_DOWN,
JOY_AUX_1, JOY_AUX_2, JOY_AUX_3, JOY_AUX_4,
-1
};
for( int ax = 0; axes[ax] != -1; ++ax )
if( DeviceI.button == axes[ax] )
return true;
return false;
}
void ScreenMapControllers2::ChangeActivePlayer()
{
m_ActivePlayerMapping = (m_ActivePlayerMapping == PLAYER_1) ? PLAYER_2 : PLAYER_1;
Message msg("ActivePlayerChanged");
msg.SetParam("NewActivePlayer",m_ActivePlayerMapping);
MESSAGEMAN->Broadcast(msg);
}
void ScreenMapControllers2::Input( const InputEventPlus &input )
{
if( input.type != IET_FIRST_PRESS && input.type != IET_REPEAT )
return; // ignore
if( IsTransitioning() )
return; // ignore
LOG->Trace( "ScreenMapControllers2::Input(): device: %d, button: %d",
input.DeviceI.device, input.DeviceI.button );
int button = input.DeviceI.button;
/* TRICKY: Some adapters map the PlayStation digital d-pad to both axes and
* buttons. We want buttons to be used for any mappings where possible
* because presses of buttons aren't mutually exclusive and presses of axes
* are (e.g. can't read presses of both Left and Right simultaneously). So,
* when the user presses a button, we'll wait until the next Update before
* adding a mapping so that we get a chance to see all input events the
* user's press of a panel. Prefer non-axis events over axis events. */
if( !m_WaitingForPress.IsZero() )
{
if( input.type != IET_FIRST_PRESS )
return;
// Don't allow function keys to be mapped.
if( input.DeviceI.device == DEVICE_KEYBOARD && (input.DeviceI.button >= KEY_F1 && input.DeviceI.button <= KEY_F12) )
{
SCREENMAN->SystemMessage( "INVALID_BUTTON" );
SCREENMAN->PlayInvalidSound();
}
else
{
if( m_DeviceIToMap.IsValid() &&
!IsAxis(m_DeviceIToMap) &&
IsAxis(input.DeviceI) )
{
LOG->Trace("Ignored input; non-axis event already received");
return; // ignore this press
}
m_DeviceIToMap = input.DeviceI;
}
}
else if( input.DeviceI.device == DEVICE_KEYBOARD )
{
switch( button )
{
// todo: m_MapControlsState checks
case KEY_UP: // mapping list up
{
if( m_MapControlsState == MCS_EditMappings )
{
if( m_iMappingChoice[m_ActivePlayerMapping] == 0 )
break;
m_iMappingChoice[m_ActivePlayerMapping]--;
}
}
break;
case KEY_DOWN: // mapping list down
{
if( m_MapControlsState == MCS_EditMappings )
{
if( m_iMappingChoice[m_ActivePlayerMapping] == m_iNumMappingRows[m_ActivePlayerMapping] )
break;
m_iMappingChoice[m_ActivePlayerMapping]++;
}
}
break;
case KEY_LEFT: // on P2, changing to P1
{
if( m_MapControlsState == MCS_EditMappings )
{
if(m_ActivePlayerMapping == PLAYER_2)
ChangeActivePlayer();
}
}
break;
case KEY_RIGHT: // on P1, changing to P2
{
if( m_MapControlsState == MCS_EditMappings )
{
if(m_ActivePlayerMapping == PLAYER_1)
ChangeActivePlayer();
}
}
break;
case KEY_DEL:
case KEY_BACK:
if( m_MapControlsState == MCS_EditMappings )
{
// clear mapping
/*
if( m_iMappingChoice[m_ActivePlayerMapping] == m_iNumMappingRows[m_ActivePlayerMapping] )
break; // on "add"
{
// stuff
m_soundDelete.Play();
// commit to disk after each change
INPUTMAPPER->SaveMappingsToDisk();
}
*/
}
break;
case KEY_ESC:
{
if(m_MapControlsState == MCS_EditMappings)
{
// xxx: make sure it's not getting a button.
m_MapControlsState = MCS_Button;
SCREENMAN->PlayCancelSound();
}
else
{
// Quit the screen.
SCREENMAN->PlayStartSound();
StartTransitioningScreen( SM_GoToNextScreen );
}
}
break;
case KEY_ENTER:
case KEY_KP_ENTER:
{
if( m_MapControlsState == MCS_EditMappings )
{
// map button
LOG->Trace("got an enter press...");
LOG->Trace( ssprintf("current choice: %i",m_iMappingChoice[m_ActivePlayerMapping]) );
if( m_iMappingChoice[m_ActivePlayerMapping] == m_iNumMappingRows[m_ActivePlayerMapping] )
{
// add
LOG->Trace("Adding a new mapping");
}
else
{
// replace
LOG->Trace("Replacing an existing mapping");
}
/*
m_WaitingForPress.Touch();
m_DeviceIToMap.MakeInvalid();
SCREENMAN->PlayStartSound();
*/
}
}
break;
}
}
ScreenWithMenuElements::Input( input ); // default handler
Refresh();
}
void ScreenMapControllers2::Refresh()
{
// update mapping scrollers
UpdateMappingScrollers();
}
void ScreenMapControllers2::HandleMessage( const Message &msg )
{
if( msg == Message_AutoJoyMappingApplied )
{
Refresh();
}
ScreenWithMenuElements::HandleMessage( msg );
}
void ScreenMapControllers2::MenuStart( const InputEventPlus &input )
{
// MCS_EditMappings is handled in Input() above.
if( m_MapControlsState == MCS_Button )
{
m_MapControlsState = MCS_EditMappings;
}
}
void ScreenMapControllers2::UpdateMappingScrollers()
{
FOREACH_ENUM( GameController, c )
{
PlayerNumber pn = (PlayerNumber)c;
m_MappingScroller[pn].RemoveAllChildren();
int iLast = 0;
for(unsigned s = 0; s < NUM_SHOWN_GAME_TO_DEVICE_SLOTS; s++)
{
GameInput cur_gi( c, m_EditingButton );
DeviceInput di;
RString sInput = "";
if( INPUTMAPPER->GameToDevice( cur_gi, s, di ) )
sInput = INPUTMAN->GetDeviceSpecificInputString(di);
if( sInput != "" )
{
m_MappingLine[iLast].RemoveAllChildren();
// we have an input, add to the scroller
BitmapText *pText = new BitmapText;
pText->SetName( "MappedTo"+PlayerNumberToString(pn) );
pText->LoadFromFont( THEME->GetPathF(m_sName,"Mapping") );
ActorUtil::LoadAllCommands(pText,m_sName);
pText->PlayCommand( ((unsigned)m_iMappingChoice[pn] == s) ? "GainFocus" : "LoseFocus" );
pText->SetText( sInput );
m_MappingLine[iLast].AddChild( pText );
m_MappingLine[iLast].DeleteChildrenWhenDone();
m_MappingLine[iLast].SetName("MappingLine");
ActorUtil::LoadAllCommands(m_MappingLine[iLast],m_sName);
m_MappingScroller[pn].AddChild( &m_MappingLine[iLast] );
iLast++;
}
}
BitmapText &text = m_textAddMapping[pn];
text.LoadFromFont( THEME->GetPathF(m_sName,"AddMapping") );
text.SetName( "AddMapping"+PlayerNumberToString(pn) );
ActorUtil::LoadAllCommands( text, m_sName );
text.PlayCommand( (m_iMappingChoice[pn] == m_iNumMappingRows[pn]) ? "GainFocus" : "LoseFocus" );
text.SetText( ADD_MAPPING );
m_MappingScroller[pn].AddChild( &m_textAddMapping[c] );
iLast++;
m_iNumMappingRows[pn] = iLast;
m_MappingScroller[pn].Load2();
m_MappingScroller[pn].SetTransformFromReference( MAPPING_SCROLLER_TRANSFORM );
m_MappingScroller[pn].SetCurrentAndDestinationItem( (float)m_iMappingChoice[pn] );
}
}
// change game/system button scroller selection
void ScreenMapControllers2::ChangeInputSelection(int iDir)
{
m_InputLine[m_iInputChoice].PlayCommand("LoseFocus");
m_iInputChoice += iDir;
m_soundChange.Play();
m_InputLine[m_iInputChoice].PlayCommand("GainFocus");
// set scroller
m_InputScroller.SetCurrentAndDestinationItem( (float)m_iInputChoice );
// set current game button
KeyToMap *pKey = &m_KeysToMap[m_iInputChoice];
m_EditingButton = pKey->m_GameButton;
}
void ScreenMapControllers2::MenuUp( const InputEventPlus &input )
{
if( m_MapControlsState == MCS_Button )
{
if( m_iInputChoice == 0 ) // limit
return;
ChangeInputSelection(-1);
}
}
void ScreenMapControllers2::MenuDown( const InputEventPlus &input )
{
if( m_MapControlsState == MCS_Button )
{
if( m_iInputChoice == (int)m_KeysToMap.size()-1 ) // limit
return;
ChangeInputSelection(1);
}
}
void ScreenMapControllers2::TweenOnScreen()
{
ScreenWithMenuElements::TweenOnScreen();
m_InputScroller.SetCurrentAndDestinationItem( (float)m_iInputChoice );
}
// lua start
#include "LuaBinding.h"
/** @brief Allow Lua to have access to ScreenMapControllers2. */
class LunaScreenMapControllers2: public Luna<ScreenMapControllers2>
{
public:
//static int MapControlsState( T* p, lua_State *L ) //
//static int GetEditingGameButton( T* p, lua_State *L ) // GetEditingGameButton()
DEFINE_METHOD( GetInputIndex, GetInputIndex() );
DEFINE_METHOD( GetNumInputs, GetNumInputs() );
LunaScreenMapControllers2()
{
//ADD_METHOD( GetEditingGameButton );
ADD_METHOD( GetInputIndex );
ADD_METHOD( GetNumInputs );
//ADD_METHOD( MapControlsState );
}
};
LUA_REGISTER_DERIVED_CLASS( ScreenMapControllers2, ScreenWithMenuElements )
/*
* (c) 2011 AJ Kelly
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
-136
View File
@@ -1,136 +0,0 @@
/* ScreenMapControllers2 - Maps device input to game buttons. */
#ifndef SCREEN_MAP_CONTROLLERS2_H
#define SCREEN_MAP_CONTROLLERS2_H
#include "ScreenWithMenuElements.h"
#include "BitmapText.h"
#include "InputMapper.h"
#include "ActorScroller.h"
#include "RageSound.h"
#include "EnumHelper.h"
#include "ThemeMetric.h"
/* old inputmapper consts:
const int NUM_GAME_TO_DEVICE_SLOTS = 5; // five device inputs may map to one game input
const int NUM_SHOWN_GAME_TO_DEVICE_SLOTS = 3;
const int NUM_USER_GAME_TO_DEVICE_SLOTS = 2;
*/
const int MAPPING_LINE = NUM_SHOWN_GAME_TO_DEVICE_SLOTS+1; // +1 for "Add Mapping"
enum MapControlsState
{
MCS_Button, // which button to edit mappings for
MCS_EditMappings, // player is editing mappings
NUM_MapControlsState,
MapControlsState_Invalid
};
const RString& MapControlsStateToString( MapControlsState mct );
LuaDeclareType( MapControlsState );
class ScreenMapControllers2 : public ScreenWithMenuElements
{
public:
ScreenMapControllers2();
virtual void Init();
virtual void BeginScreen();
//virtual void EndScreen();
virtual void Update( float fDeltaTime );
virtual bool Input( const InputEventPlus &input );
virtual bool MenuUp( const InputEventPlus &input );
virtual bool MenuDown( const InputEventPlus &input );
virtual bool MenuStart( const InputEventPlus &input );
virtual void TweenOnScreen();
MapControlsState GetMapControlsState(){ return m_MapControlsState; }
GameButton GetEditingGameButton() { return m_EditingButton; }
int GetInputIndex(){ return m_iInputChoice; }
int GetNumInputs(){ return m_KeysToMap.size(); }
int GetMappingIndex(PlayerNumber pn){ return m_iMappingChoice[pn]; }
// Lua
virtual void PushSelf( lua_State *L );
protected:
virtual void HandleMessage( const Message &msg );
void ChangeActivePlayer();
void ChangeInputSelection(int iDir);
void UpdateMappingScrollers();
void Refresh();
MapControlsState m_MapControlsState;
RageTimer m_WaitingForPress;
DeviceInput m_DeviceIToMap;
struct KeyToMap
{
GameButton m_GameButton;
BitmapText* m_textLabel;
};
vector<KeyToMap> m_KeysToMap;
BitmapText m_textDevices;
//vector<BitmapText> m_textMappingLabels[NUM_PLAYERS];
BitmapText m_textAddMapping[NUM_PLAYERS];
// possible inputs
int m_iInputChoice;
ActorScroller m_InputScroller;
ActorFrame m_InputLine[NUM_GameButton];
ThemeMetric<bool> WRAP_INPUT_SCROLLER;
ThemeMetric<bool> LOOP_INPUT_SCROLLER;
ThemeMetric<float> INPUT_SCROLLER_SECONDS_PER_ITEM;
ThemeMetric<float> INPUT_SCROLLER_NUM_ITEMS_TO_DRAW;
ThemeMetric<LuaReference> INPUT_SCROLLER_TRANSFORM;
ThemeMetric<int> INPUT_SCROLLER_SUBDIVISIONS;
// per-player button mappings.
GameButton m_EditingButton;
PlayerNumber m_ActivePlayerMapping;
int m_iMappingChoice[NUM_PLAYERS];
int m_iNumMappingRows[NUM_PLAYERS];
ActorScroller m_MappingScroller[NUM_PLAYERS];
ActorFrame m_MappingLine[MAPPING_LINE];
ThemeMetric<bool> WRAP_MAPPING_SCROLLER;
ThemeMetric<bool> LOOP_MAPPING_SCROLLER;
ThemeMetric<float> MAPPING_SCROLLER_SECONDS_PER_ITEM;
ThemeMetric<float> MAPPING_SCROLLER_NUM_ITEMS_TO_DRAW;
ThemeMetric<LuaReference> MAPPING_SCROLLER_TRANSFORM;
ThemeMetric<int> MAPPING_SCROLLER_SUBDIVISIONS;
// should be handled in lua
//BitmapText m_textLabel[NUM_GameController];
RageSound m_soundChange;
RageSound m_soundDelete;
};
#endif
/*
* (c) 2011 AJ Kelly
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/