2021-12-13 12:12:54 +00:00
/* PCSX2 - PS2 Emulator for PCs
* Copyright ( C ) 2002 - 2022 PCSX2 Dev Team
*
* PCSX2 is free software : you can redistribute it and / or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found -
* ation , either version 3 of the License , or ( at your option ) any later version .
*
* PCSX2 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 GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License along with PCSX2 .
* If not , see < http : //www.gnu.org/licenses/>.
*/
# include "PrecompiledHeader.h"
2022-12-04 15:00:06 +00:00
# include <QtCore/QDir>
2022-08-05 13:52:16 +00:00
# include <QtWidgets/QInputDialog>
2022-03-25 12:16:21 +00:00
# include <QtWidgets/QMenu>
2021-12-13 12:12:54 +00:00
# include <QtWidgets/QMessageBox>
2022-12-04 15:00:06 +00:00
# include <QtWidgets/QScrollArea>
2021-12-13 12:12:54 +00:00
# include <algorithm>
2022-12-04 15:00:06 +00:00
# include "fmt/format.h"
# include "common/StringUtil.h"
2023-05-13 04:30:41 +00:00
# include "pcsx2/Host.h"
2023-07-25 15:10:02 +00:00
# include "pcsx2/SIO/Pad/Pad.h"
2021-12-13 12:12:54 +00:00
2022-06-08 12:15:10 +00:00
# include "Settings/ControllerBindingWidgets.h"
2023-10-14 08:45:09 +00:00
# include "Settings/ControllerSettingsWindow.h"
2022-06-08 12:15:10 +00:00
# include "Settings/ControllerSettingWidgetBinder.h"
2023-10-14 08:45:09 +00:00
# include "Settings/SettingsWindow.h"
2022-09-07 09:20:50 +00:00
# include "QtHost.h"
2021-12-13 12:12:54 +00:00
# include "QtUtils.h"
# include "SettingWidgetBinder.h"
2022-12-04 15:00:06 +00:00
# include "ui_USBBindingWidget_DrivingForce.h"
# include "ui_USBBindingWidget_GTForce.h"
2023-07-23 05:35:32 +00:00
# include "ui_USBBindingWidget_GunCon2.h"
2021-12-13 12:12:54 +00:00
2023-10-14 08:45:09 +00:00
ControllerBindingWidget : : ControllerBindingWidget ( QWidget * parent , ControllerSettingsWindow * dialog , u32 port )
2021-12-13 12:12:54 +00:00
: QWidget ( parent )
, m_dialog ( dialog )
2023-01-30 10:24:37 +00:00
, m_config_section ( fmt : : format ( " Pad{} " , port + 1 ) )
2021-12-13 12:12:54 +00:00
, m_port_number ( port )
{
m_ui . setupUi ( this ) ;
2023-01-30 10:24:37 +00:00
m_ui . groupBox - > setTitle ( tr ( " Controller Port %1 " ) . arg ( port + 1 ) ) ;
2021-12-13 12:12:54 +00:00
populateControllerTypes ( ) ;
onTypeChanged ( ) ;
2023-07-29 03:42:45 +00:00
ControllerSettingWidgetBinder : : BindWidgetToInputProfileString ( m_dialog - > getProfileSettingsInterface ( ) ,
m_ui . controllerType , m_config_section , " Type " , Pad : : GetControllerInfo ( Pad : : GetDefaultPadType ( port ) ) - > name ) ;
2022-06-08 12:15:10 +00:00
2022-03-25 12:16:21 +00:00
connect ( m_ui . controllerType , QOverload < int > : : of ( & QComboBox : : currentIndexChanged ) , this , & ControllerBindingWidget : : onTypeChanged ) ;
2022-08-05 13:52:16 +00:00
connect ( m_ui . bindings , & QPushButton : : clicked , this , & ControllerBindingWidget : : onBindingsClicked ) ;
connect ( m_ui . settings , & QPushButton : : clicked , this , & ControllerBindingWidget : : onSettingsClicked ) ;
connect ( m_ui . macros , & QPushButton : : clicked , this , & ControllerBindingWidget : : onMacrosClicked ) ;
connect ( m_ui . automaticBinding , & QPushButton : : clicked , this , & ControllerBindingWidget : : onAutomaticBindingClicked ) ;
connect ( m_ui . clearBindings , & QPushButton : : clicked , this , & ControllerBindingWidget : : onClearBindingsClicked ) ;
2021-12-13 12:12:54 +00:00
}
2022-03-25 12:16:21 +00:00
ControllerBindingWidget : : ~ ControllerBindingWidget ( ) = default ;
2021-12-13 12:12:54 +00:00
2022-06-08 12:15:10 +00:00
QIcon ControllerBindingWidget : : getIcon ( ) const
{
2022-08-05 13:52:16 +00:00
return m_bindings_widget - > getIcon ( ) ;
2022-06-08 12:15:10 +00:00
}
2021-12-13 12:12:54 +00:00
void ControllerBindingWidget : : populateControllerTypes ( )
{
2023-07-25 15:10:02 +00:00
for ( const auto & [ name , display_name ] : Pad : : GetControllerTypeNames ( ) )
m_ui . controllerType - > addItem ( QString : : fromUtf8 ( display_name ) , QString : : fromUtf8 ( name ) ) ;
2021-12-13 12:12:54 +00:00
}
void ControllerBindingWidget : : onTypeChanged ( )
{
2022-08-05 13:52:16 +00:00
const bool is_initializing = ( m_ui . stackedWidget - > count ( ) = = 0 ) ;
2023-07-29 03:42:45 +00:00
const std : : string type_name = m_dialog - > getStringValue (
m_config_section . c_str ( ) , " Type " , Pad : : GetControllerInfo ( Pad : : GetDefaultPadType ( m_port_number ) ) - > name ) ;
const Pad : : ControllerInfo * cinfo = Pad : : GetControllerInfoByName ( type_name ) ;
if ( ! cinfo )
{
Console . Error ( fmt : : format ( " Invalid controller type name '{}' in config, ignoring. " , type_name ) ) ;
cinfo = Pad : : GetControllerInfo ( Pad : : ControllerType : : NotConnected ) ;
}
m_controller_type = cinfo - > type ;
2022-06-08 12:15:10 +00:00
2022-08-05 13:52:16 +00:00
if ( m_bindings_widget )
2021-12-13 12:12:54 +00:00
{
2022-08-05 13:52:16 +00:00
m_ui . stackedWidget - > removeWidget ( m_bindings_widget ) ;
delete m_bindings_widget ;
m_bindings_widget = nullptr ;
2021-12-13 12:12:54 +00:00
}
2022-08-05 13:52:16 +00:00
if ( m_settings_widget )
2021-12-13 12:12:54 +00:00
{
2022-08-05 13:52:16 +00:00
m_ui . stackedWidget - > removeWidget ( m_settings_widget ) ;
delete m_settings_widget ;
m_settings_widget = nullptr ;
2021-12-13 12:12:54 +00:00
}
2022-08-05 13:52:16 +00:00
if ( m_macros_widget )
{
m_ui . stackedWidget - > removeWidget ( m_macros_widget ) ;
delete m_macros_widget ;
m_macros_widget = nullptr ;
}
2023-07-29 03:42:45 +00:00
const bool has_settings = ( ! cinfo - > settings . empty ( ) ) ;
const bool has_macros = ( ! cinfo - > bindings . empty ( ) ) ;
2022-08-05 13:52:16 +00:00
m_ui . settings - > setEnabled ( has_settings ) ;
m_ui . macros - > setEnabled ( has_macros ) ;
2021-12-13 12:12:54 +00:00
2023-07-29 03:42:45 +00:00
if ( cinfo - > type = = Pad : : ControllerType : : DualShock2 )
2023-06-11 06:06:40 +00:00
{
2022-08-05 13:52:16 +00:00
m_bindings_widget = ControllerBindingWidget_DualShock2 : : createInstance ( this ) ;
2023-06-11 06:06:40 +00:00
}
2023-07-29 03:42:45 +00:00
else if ( cinfo - > type = = Pad : : ControllerType : : Guitar )
2023-06-11 06:06:40 +00:00
{
m_bindings_widget = ControllerBindingWidget_Guitar : : createInstance ( this ) ;
}
2021-12-13 12:12:54 +00:00
else
2023-06-11 06:06:40 +00:00
{
2022-08-05 13:52:16 +00:00
m_bindings_widget = new ControllerBindingWidget_Base ( this ) ;
2023-06-11 06:06:40 +00:00
}
2021-12-13 12:12:54 +00:00
2022-08-05 13:52:16 +00:00
m_ui . stackedWidget - > addWidget ( m_bindings_widget ) ;
m_ui . stackedWidget - > setCurrentWidget ( m_bindings_widget ) ;
if ( has_settings )
{
2023-06-19 12:03:10 +00:00
m_settings_widget = new ControllerCustomSettingsWidget (
2023-07-25 15:10:02 +00:00
cinfo - > settings , m_config_section , std : : string ( ) , " Pad " , getDialog ( ) , m_ui . stackedWidget ) ;
2022-08-05 13:52:16 +00:00
m_ui . stackedWidget - > addWidget ( m_settings_widget ) ;
}
if ( has_macros )
{
m_macros_widget = new ControllerMacroWidget ( this ) ;
m_ui . stackedWidget - > addWidget ( m_macros_widget ) ;
}
updateHeaderToolButtons ( ) ;
2022-06-08 12:15:10 +00:00
// no need to do this on first init, only changes
if ( ! is_initializing )
m_dialog - > updateListDescription ( m_port_number , this ) ;
2021-12-13 12:12:54 +00:00
}
2022-08-05 13:52:16 +00:00
void ControllerBindingWidget : : updateHeaderToolButtons ( )
{
const QWidget * current_widget = m_ui . stackedWidget - > currentWidget ( ) ;
const QSignalBlocker bindings_sb ( m_ui . bindings ) ;
const QSignalBlocker settings_sb ( m_ui . settings ) ;
const QSignalBlocker macros_sb ( m_ui . macros ) ;
const bool is_bindings = ( current_widget = = m_bindings_widget ) ;
m_ui . bindings - > setChecked ( is_bindings ) ;
m_ui . automaticBinding - > setEnabled ( is_bindings ) ;
m_ui . clearBindings - > setEnabled ( is_bindings ) ;
m_ui . macros - > setChecked ( current_widget = = m_macros_widget ) ;
m_ui . settings - > setChecked ( ( current_widget = = m_settings_widget ) ) ;
}
void ControllerBindingWidget : : onBindingsClicked ( )
{
m_ui . stackedWidget - > setCurrentWidget ( m_bindings_widget ) ;
updateHeaderToolButtons ( ) ;
}
void ControllerBindingWidget : : onSettingsClicked ( )
{
if ( ! m_settings_widget )
return ;
m_ui . stackedWidget - > setCurrentWidget ( m_settings_widget ) ;
updateHeaderToolButtons ( ) ;
}
void ControllerBindingWidget : : onMacrosClicked ( )
{
if ( ! m_macros_widget )
return ;
m_ui . stackedWidget - > setCurrentWidget ( m_macros_widget ) ;
updateHeaderToolButtons ( ) ;
}
void ControllerBindingWidget : : onAutomaticBindingClicked ( )
2022-03-25 12:16:21 +00:00
{
QMenu menu ( this ) ;
bool added = false ;
for ( const QPair < QString , QString > & dev : m_dialog - > getDeviceList ( ) )
{
// we set it as data, because the device list could get invalidated while the menu is up
QAction * action = menu . addAction ( QStringLiteral ( " %1 (%2) " ) . arg ( dev . first ) . arg ( dev . second ) ) ;
action - > setData ( dev . first ) ;
2022-12-04 15:00:06 +00:00
connect ( action , & QAction : : triggered , this , [ this , action ] ( ) { doDeviceAutomaticBinding ( action - > data ( ) . toString ( ) ) ; } ) ;
2022-03-25 12:16:21 +00:00
added = true ;
}
if ( ! added )
{
QAction * action = menu . addAction ( tr ( " No devices available " ) ) ;
action - > setEnabled ( false ) ;
}
menu . exec ( QCursor : : pos ( ) ) ;
}
2022-08-05 13:52:16 +00:00
void ControllerBindingWidget : : onClearBindingsClicked ( )
2022-05-24 14:27:19 +00:00
{
2023-03-18 21:14:55 +00:00
//: Binding: A pair of (host button, target button); Mapping: A list of bindings covering an entire controller. These are two different things (which might be the same in your language, please make sure to verify this).
2022-05-24 14:27:19 +00:00
if ( QMessageBox : : question ( QtUtils : : GetRootWidget ( this ) , tr ( " Clear Bindings " ) ,
2023-03-18 21:14:55 +00:00
//: Binding: A pair of (host button, target button); Mapping: A list of bindings covering an entire controller. These are two different things (which might be the same in your language, please make sure to verify this).
2022-06-08 12:15:10 +00:00
tr ( " Are you sure you want to clear all bindings for this controller? This action cannot be undone. " ) ) ! = QMessageBox : : Yes )
2022-05-24 14:27:19 +00:00
{
return ;
}
2022-06-08 12:15:10 +00:00
if ( m_dialog - > isEditingGlobalSettings ( ) )
2022-05-24 14:27:19 +00:00
{
2022-09-15 14:40:34 +00:00
{
auto lock = Host : : GetSettingsLock ( ) ;
2023-07-25 15:10:02 +00:00
Pad : : ClearPortBindings ( * Host : : Internal : : GetBaseSettingsLayer ( ) , m_port_number ) ;
2022-09-15 14:40:34 +00:00
}
2022-09-07 07:44:10 +00:00
Host : : CommitBaseSettingChanges ( ) ;
2022-05-24 14:27:19 +00:00
}
2022-06-08 12:15:10 +00:00
else
{
2023-07-25 15:10:02 +00:00
Pad : : ClearPortBindings ( * m_dialog - > getProfileSettingsInterface ( ) , m_port_number ) ;
2022-09-07 07:44:10 +00:00
m_dialog - > getProfileSettingsInterface ( ) - > Save ( ) ;
2022-06-08 12:15:10 +00:00
}
2022-05-24 14:27:19 +00:00
2022-09-07 07:44:10 +00:00
// force a refresh after clearing
g_emu_thread - > applySettings ( ) ;
onTypeChanged ( ) ;
2022-05-24 14:27:19 +00:00
}
2022-03-25 12:16:21 +00:00
void ControllerBindingWidget : : doDeviceAutomaticBinding ( const QString & device )
{
std : : vector < std : : pair < GenericInputBinding , std : : string > > mapping = InputManager : : GetGenericBindingMapping ( device . toStdString ( ) ) ;
if ( mapping . empty ( ) )
{
QMessageBox : : critical ( QtUtils : : GetRootWidget ( this ) , tr ( " Automatic Binding " ) ,
2022-10-15 09:04:30 +00:00
tr ( " No generic bindings were generated for device '%1'. The controller/source may not support automatic mapping. " ) . arg ( device ) ) ;
2022-03-25 12:16:21 +00:00
return ;
}
bool result ;
2022-06-08 12:15:10 +00:00
if ( m_dialog - > isEditingGlobalSettings ( ) )
2022-03-25 12:16:21 +00:00
{
2022-09-10 03:06:04 +00:00
{
auto lock = Host : : GetSettingsLock ( ) ;
2023-07-25 15:10:02 +00:00
result = Pad : : MapController ( * Host : : Internal : : GetBaseSettingsLayer ( ) , m_port_number , mapping ) ;
2022-09-10 03:06:04 +00:00
}
2022-09-07 07:44:10 +00:00
if ( result )
Host : : CommitBaseSettingChanges ( ) ;
2022-03-25 12:16:21 +00:00
}
2022-06-08 12:15:10 +00:00
else
{
2023-07-25 15:10:02 +00:00
result = Pad : : MapController ( * m_dialog - > getProfileSettingsInterface ( ) , m_port_number , mapping ) ;
2022-09-07 07:44:10 +00:00
if ( result )
{
m_dialog - > getProfileSettingsInterface ( ) - > Save ( ) ;
g_emu_thread - > reloadInputBindings ( ) ;
}
2022-06-08 12:15:10 +00:00
}
2022-03-25 12:16:21 +00:00
2022-05-24 14:27:19 +00:00
// force a refresh after mapping
2022-03-25 12:16:21 +00:00
if ( result )
2022-09-07 07:44:10 +00:00
{
g_emu_thread - > applySettings ( ) ;
onTypeChanged ( ) ;
}
2022-03-25 12:16:21 +00:00
}
2022-08-05 13:52:16 +00:00
//////////////////////////////////////////////////////////////////////////
ControllerMacroWidget : : ControllerMacroWidget ( ControllerBindingWidget * parent )
: QWidget ( parent )
{
m_ui . setupUi ( this ) ;
setWindowTitle ( tr ( " Controller Port %1 Macros " ) . arg ( parent - > getPortNumber ( ) + 1u ) ) ;
createWidgets ( parent ) ;
}
ControllerMacroWidget : : ~ ControllerMacroWidget ( ) = default ;
void ControllerMacroWidget : : updateListItem ( u32 index )
{
2023-03-18 21:14:55 +00:00
//: This is the full text that appears in each option of the 16 available macros, and reads like this:\n\nMacro 1\nNot Configured/Buttons configured
2022-12-04 15:00:06 +00:00
m_ui . portList - > item ( static_cast < int > ( index ) ) - > setText ( tr ( " Macro %1 \n %2 " ) . arg ( index + 1 ) . arg ( m_macros [ index ] - > getSummary ( ) ) ) ;
2022-08-05 13:52:16 +00:00
}
void ControllerMacroWidget : : createWidgets ( ControllerBindingWidget * parent )
{
for ( u32 i = 0 ; i < NUM_MACROS ; i + + )
{
m_macros [ i ] = new ControllerMacroEditWidget ( this , parent , i ) ;
m_ui . container - > addWidget ( m_macros [ i ] ) ;
QListWidgetItem * item = new QListWidgetItem ( ) ;
item - > setIcon ( QIcon : : fromTheme ( QStringLiteral ( " flashlight-line " ) ) ) ;
m_ui . portList - > addItem ( item ) ;
updateListItem ( i ) ;
}
m_ui . portList - > setCurrentRow ( 0 ) ;
m_ui . container - > setCurrentIndex ( 0 ) ;
connect ( m_ui . portList , & QListWidget : : currentRowChanged , m_ui . container , & QStackedWidget : : setCurrentIndex ) ;
}
//////////////////////////////////////////////////////////////////////////
2022-12-04 15:00:06 +00:00
ControllerMacroEditWidget : : ControllerMacroEditWidget ( ControllerMacroWidget * parent , ControllerBindingWidget * bwidget , u32 index )
2022-08-05 13:52:16 +00:00
: QWidget ( parent )
, m_parent ( parent )
, m_bwidget ( bwidget )
, m_index ( index )
{
m_ui . setupUi ( this ) ;
2023-10-14 08:45:09 +00:00
ControllerSettingsWindow * dialog = m_bwidget - > getDialog ( ) ;
2022-08-05 13:52:16 +00:00
const std : : string & section = m_bwidget - > getConfigSection ( ) ;
2023-07-25 15:10:02 +00:00
const Pad : : ControllerInfo * cinfo = Pad : : GetControllerInfo ( m_bwidget - > getControllerType ( ) ) ;
2022-08-05 13:52:16 +00:00
if ( ! cinfo )
{
// Shouldn't ever happen.
return ;
}
// load binds (single string joined by &)
2022-12-04 15:00:06 +00:00
const std : : string binds_string ( dialog - > getStringValue ( section . c_str ( ) , fmt : : format ( " Macro{}Binds " , index + 1u ) . c_str ( ) , " " ) ) ;
2022-08-05 13:52:16 +00:00
const std : : vector < std : : string_view > buttons_split ( StringUtil : : SplitString ( binds_string , ' & ' , true ) ) ;
for ( const std : : string_view & button : buttons_split )
{
2023-07-25 15:10:02 +00:00
for ( const InputBindingInfo & bi : cinfo - > bindings )
2022-08-05 13:52:16 +00:00
{
2023-07-25 15:10:02 +00:00
if ( button = = bi . name )
2022-08-05 13:52:16 +00:00
{
2023-07-25 15:10:02 +00:00
m_binds . push_back ( & bi ) ;
2022-08-05 13:52:16 +00:00
break ;
}
}
}
// populate list view
2023-07-25 15:10:02 +00:00
for ( const InputBindingInfo & bi : cinfo - > bindings )
2022-08-05 13:52:16 +00:00
{
2022-11-27 08:36:23 +00:00
if ( bi . bind_type = = InputBindingInfo : : Type : : Motor )
2022-08-05 13:52:16 +00:00
continue ;
QListWidgetItem * item = new QListWidgetItem ( ) ;
2023-06-19 12:03:10 +00:00
item - > setText ( qApp - > translate ( " Pad " , bi . display_name ) ) ;
2022-12-04 15:00:06 +00:00
item - > setCheckState ( ( std : : find ( m_binds . begin ( ) , m_binds . end ( ) , & bi ) ! = m_binds . end ( ) ) ? Qt : : Checked : Qt : : Unchecked ) ;
2022-08-05 13:52:16 +00:00
m_ui . bindList - > addItem ( item ) ;
}
2023-03-03 10:53:39 +00:00
ControllerSettingWidgetBinder : : BindWidgetToInputProfileNormalized (
dialog - > getProfileSettingsInterface ( ) , m_ui . pressure , section , fmt : : format ( " Macro{}Pressure " , index + 1u ) , 100.0f , 1.0f ) ;
2023-07-25 15:10:02 +00:00
ControllerSettingWidgetBinder : : BindWidgetToInputProfileNormalized (
dialog - > getProfileSettingsInterface ( ) , m_ui . deadzone , section , fmt : : format ( " Macro{}Deadzone " , index + 1u ) , 100.0f , 0.0f ) ;
2023-03-03 10:53:39 +00:00
connect ( m_ui . pressure , & QSlider : : valueChanged , this , & ControllerMacroEditWidget : : onPressureChanged ) ;
2023-07-25 15:10:02 +00:00
connect ( m_ui . deadzone , & QSlider : : valueChanged , this , & ControllerMacroEditWidget : : onDeadzoneChanged ) ;
2023-03-03 10:53:39 +00:00
onPressureChanged ( ) ;
2023-07-25 15:10:02 +00:00
onDeadzoneChanged ( ) ;
2023-03-03 10:53:39 +00:00
2022-08-05 13:52:16 +00:00
m_frequency = dialog - > getIntValue ( section . c_str ( ) , fmt : : format ( " Macro{}Frequency " , index + 1u ) . c_str ( ) , 0 ) ;
updateFrequencyText ( ) ;
2022-12-04 15:00:06 +00:00
m_ui . trigger - > initialize (
dialog - > getProfileSettingsInterface ( ) , InputBindingInfo : : Type : : Macro , section , fmt : : format ( " Macro{} " , index + 1u ) ) ;
2022-08-05 13:52:16 +00:00
connect ( m_ui . increaseFrequency , & QAbstractButton : : clicked , this , [ this ] ( ) { modFrequency ( 1 ) ; } ) ;
connect ( m_ui . decreateFrequency , & QAbstractButton : : clicked , this , [ this ] ( ) { modFrequency ( - 1 ) ; } ) ;
connect ( m_ui . setFrequency , & QAbstractButton : : clicked , this , & ControllerMacroEditWidget : : onSetFrequencyClicked ) ;
connect ( m_ui . bindList , & QListWidget : : itemChanged , this , & ControllerMacroEditWidget : : updateBinds ) ;
}
ControllerMacroEditWidget : : ~ ControllerMacroEditWidget ( ) = default ;
QString ControllerMacroEditWidget : : getSummary ( ) const
{
QString str ;
2022-11-27 08:27:17 +00:00
for ( const InputBindingInfo * bi : m_binds )
2022-08-05 13:52:16 +00:00
{
if ( ! str . isEmpty ( ) )
str + = static_cast < QChar > ( ' / ' ) ;
2023-06-19 12:03:10 +00:00
str + = qApp - > translate ( " Pad " , bi - > display_name ) ;
2022-08-05 13:52:16 +00:00
}
return str . isEmpty ( ) ? tr ( " Not Configured " ) : str ;
}
2023-03-03 10:53:39 +00:00
void ControllerMacroEditWidget : : onPressureChanged ( )
{
m_ui . pressureValue - > setText ( tr ( " %1% " ) . arg ( m_ui . pressure - > value ( ) ) ) ;
}
2023-07-25 15:10:02 +00:00
void ControllerMacroEditWidget : : onDeadzoneChanged ( )
{
m_ui . deadzoneValue - > setText ( tr ( " %1% " ) . arg ( m_ui . deadzone - > value ( ) ) ) ;
}
2022-08-05 13:52:16 +00:00
void ControllerMacroEditWidget : : onSetFrequencyClicked ( )
{
bool okay ;
2022-12-04 15:00:06 +00:00
int new_freq = QInputDialog : : getInt (
this , tr ( " Set Frequency " ) , tr ( " Frequency: " ) , static_cast < int > ( m_frequency ) , 0 , std : : numeric_limits < int > : : max ( ) , 1 , & okay ) ;
2022-08-05 13:52:16 +00:00
if ( ! okay )
return ;
m_frequency = static_cast < u32 > ( new_freq ) ;
updateFrequency ( ) ;
}
void ControllerMacroEditWidget : : modFrequency ( s32 delta )
{
if ( delta < 0 & & m_frequency = = 0 )
return ;
m_frequency = static_cast < u32 > ( static_cast < s32 > ( m_frequency ) + delta ) ;
updateFrequency ( ) ;
}
void ControllerMacroEditWidget : : updateFrequency ( )
{
2022-12-04 15:00:06 +00:00
m_bwidget - > getDialog ( ) - > setIntValue (
m_bwidget - > getConfigSection ( ) . c_str ( ) , fmt : : format ( " Macro{}Frequency " , m_index + 1u ) . c_str ( ) , static_cast < s32 > ( m_frequency ) ) ;
2022-08-05 13:52:16 +00:00
updateFrequencyText ( ) ;
}
void ControllerMacroEditWidget : : updateFrequencyText ( )
{
if ( m_frequency = = 0 )
m_ui . frequencyText - > setText ( tr ( " Macro will not repeat. " ) ) ;
else
m_ui . frequencyText - > setText ( tr ( " Macro will toggle buttons every %1 frames. " ) . arg ( m_frequency ) ) ;
}
void ControllerMacroEditWidget : : updateBinds ( )
{
2023-10-14 08:45:09 +00:00
ControllerSettingsWindow * dialog = m_bwidget - > getDialog ( ) ;
2023-07-25 15:10:02 +00:00
const Pad : : ControllerInfo * cinfo = Pad : : GetControllerInfo ( m_bwidget - > getControllerType ( ) ) ;
2022-08-05 13:52:16 +00:00
if ( ! cinfo )
return ;
2022-11-27 08:27:17 +00:00
std : : vector < const InputBindingInfo * > new_binds ;
2023-07-25 15:10:02 +00:00
for ( u32 i = 0 , bind_index = 0 ; i < static_cast < u32 > ( cinfo - > bindings . size ( ) ) ; i + + )
2022-08-05 13:52:16 +00:00
{
2022-11-27 08:27:17 +00:00
const InputBindingInfo & bi = cinfo - > bindings [ i ] ;
2022-11-27 08:36:23 +00:00
if ( bi . bind_type = = InputBindingInfo : : Type : : Motor )
2022-08-05 13:52:16 +00:00
continue ;
const QListWidgetItem * item = m_ui . bindList - > item ( static_cast < int > ( bind_index ) ) ;
bind_index + + ;
if ( ! item )
{
// shouldn't happen
continue ;
}
if ( item - > checkState ( ) = = Qt : : Checked )
new_binds . push_back ( & bi ) ;
}
if ( m_binds = = new_binds )
return ;
m_binds = std : : move ( new_binds ) ;
std : : string binds_string ;
2022-11-27 08:27:17 +00:00
for ( const InputBindingInfo * bi : m_binds )
2022-08-05 13:52:16 +00:00
{
if ( ! binds_string . empty ( ) )
binds_string . append ( " & " ) ;
binds_string . append ( bi - > name ) ;
}
const std : : string & section = m_bwidget - > getConfigSection ( ) ;
const std : : string key ( fmt : : format ( " Macro{}Binds " , m_index + 1u ) ) ;
if ( binds_string . empty ( ) )
dialog - > clearSettingValue ( section . c_str ( ) , key . c_str ( ) ) ;
else
dialog - > setStringValue ( section . c_str ( ) , key . c_str ( ) , binds_string . c_str ( ) ) ;
m_parent - > updateListItem ( m_index ) ;
}
//////////////////////////////////////////////////////////////////////////
2023-07-19 13:53:42 +00:00
ControllerCustomSettingsWidget : : ControllerCustomSettingsWidget ( std : : span < const SettingInfo > settings , std : : string config_section ,
2023-10-14 08:45:09 +00:00
std : : string config_prefix , const char * translation_ctx , ControllerSettingsWindow * dialog , QWidget * parent_widget )
2022-08-05 13:52:16 +00:00
: QWidget ( parent_widget )
2022-12-04 15:00:06 +00:00
, m_settings ( settings )
, m_config_section ( std : : move ( config_section ) )
, m_config_prefix ( std : : move ( config_prefix ) )
, m_dialog ( dialog )
2022-08-05 13:52:16 +00:00
{
2022-12-04 15:00:06 +00:00
if ( settings . empty ( ) )
2022-08-05 13:52:16 +00:00
return ;
2023-01-30 10:24:37 +00:00
QScrollArea * sarea = new QScrollArea ( this ) ;
QWidget * swidget = new QWidget ( sarea ) ;
sarea - > setWidget ( swidget ) ;
sarea - > setWidgetResizable ( true ) ;
sarea - > setFrameShape ( QFrame : : StyledPanel ) ;
sarea - > setFrameShadow ( QFrame : : Sunken ) ;
QGridLayout * swidget_layout = new QGridLayout ( swidget ) ;
createSettingWidgets ( translation_ctx , swidget , swidget_layout ) ;
2022-08-05 13:52:16 +00:00
QVBoxLayout * layout = new QVBoxLayout ( this ) ;
layout - > setContentsMargins ( 0 , 0 , 0 , 0 ) ;
2023-01-30 10:24:37 +00:00
layout - > addWidget ( sarea ) ;
2022-08-05 13:52:16 +00:00
}
ControllerCustomSettingsWidget : : ~ ControllerCustomSettingsWidget ( ) = default ;
2022-12-04 15:00:06 +00:00
static std : : tuple < QString , QString > getPrefixAndSuffixForIntFormat ( const QString & format )
{
QString prefix , suffix ;
QRegularExpression re ( QStringLiteral ( " (.*) % . * d ( . * ) " )) ;
QRegularExpressionMatch match ( re . match ( format ) ) ;
if ( match . isValid ( ) )
{
prefix = match . captured ( 1 ) . replace ( QStringLiteral ( " %% " ) , QStringLiteral ( " % " ) ) ;
suffix = match . captured ( 2 ) . replace ( QStringLiteral ( " %% " ) , QStringLiteral ( " % " ) ) ;
}
return std : : tie ( prefix , suffix ) ;
}
static std : : tuple < QString , QString , int > getPrefixAndSuffixForFloatFormat ( const QString & format )
{
QString prefix , suffix ;
int decimals = - 1 ;
QRegularExpression re ( QStringLiteral ( " (.*) % . * ( [ 0 - 9 ] + ) f ( . * ) " )) ;
QRegularExpressionMatch match ( re . match ( format ) ) ;
if ( match . isValid ( ) )
{
prefix = match . captured ( 1 ) . replace ( QStringLiteral ( " %% " ) , QStringLiteral ( " % " ) ) ;
suffix = match . captured ( 3 ) . replace ( QStringLiteral ( " %% " ) , QStringLiteral ( " % " ) ) ;
bool decimals_ok ;
decimals = match . captured ( 2 ) . toInt ( & decimals_ok ) ;
if ( ! decimals_ok )
decimals = - 1 ;
}
else
{
re = QRegularExpression ( QStringLiteral ( " (.*)%.*f(.*) " ) ) ;
match = re . match ( format ) ;
prefix = match . captured ( 1 ) . replace ( QStringLiteral ( " %% " ) , QStringLiteral ( " % " ) ) ;
suffix = match . captured ( 2 ) . replace ( QStringLiteral ( " %% " ) , QStringLiteral ( " % " ) ) ;
}
return std : : tie ( prefix , suffix , decimals ) ;
}
void ControllerCustomSettingsWidget : : createSettingWidgets ( const char * translation_ctx , QWidget * widget_parent , QGridLayout * layout )
2022-08-05 13:52:16 +00:00
{
2022-12-04 15:00:06 +00:00
SettingsInterface * sif = m_dialog - > getProfileSettingsInterface ( ) ;
2022-08-05 13:52:16 +00:00
int current_row = 0 ;
2022-12-04 15:00:06 +00:00
for ( const SettingInfo & si : m_settings )
2022-08-05 13:52:16 +00:00
{
2022-12-04 15:00:06 +00:00
std : : string key_name = m_config_prefix + si . name ;
2022-08-05 13:52:16 +00:00
switch ( si . type )
{
2022-11-27 08:27:17 +00:00
case SettingInfo : : Type : : Boolean :
2022-08-05 13:52:16 +00:00
{
2022-12-04 15:00:06 +00:00
QCheckBox * cb = new QCheckBox ( qApp - > translate ( translation_ctx , si . display_name ) , widget_parent ) ;
2022-08-07 06:37:25 +00:00
cb - > setObjectName ( QString : : fromUtf8 ( si . name ) ) ;
2022-12-04 15:00:06 +00:00
ControllerSettingWidgetBinder : : BindWidgetToInputProfileBool (
sif , cb , m_config_section , std : : move ( key_name ) , si . BooleanDefaultValue ( ) ) ;
2022-08-05 13:52:16 +00:00
layout - > addWidget ( cb , current_row , 0 , 1 , 4 ) ;
current_row + + ;
}
break ;
2022-11-27 08:27:17 +00:00
case SettingInfo : : Type : : Integer :
2022-08-05 13:52:16 +00:00
{
QSpinBox * sb = new QSpinBox ( widget_parent ) ;
2022-08-07 06:37:25 +00:00
sb - > setObjectName ( QString : : fromUtf8 ( si . name ) ) ;
2022-08-05 13:52:16 +00:00
sb - > setMinimum ( si . IntegerMinValue ( ) ) ;
sb - > setMaximum ( si . IntegerMaxValue ( ) ) ;
sb - > setSingleStep ( si . IntegerStepValue ( ) ) ;
2022-12-04 15:00:06 +00:00
if ( si . format )
{
2023-10-02 04:46:51 +00:00
const auto [ prefix , suffix ] = getPrefixAndSuffixForIntFormat ( qApp - > translate ( translation_ctx , si . format ) ) ;
2022-12-04 15:00:06 +00:00
sb - > setPrefix ( prefix ) ;
sb - > setSuffix ( suffix ) ;
}
2023-01-30 10:38:23 +00:00
ControllerSettingWidgetBinder : : BindWidgetToInputProfileInt (
sif , sb , m_config_section , std : : move ( key_name ) , si . IntegerDefaultValue ( ) ) ;
2022-12-04 15:00:06 +00:00
layout - > addWidget ( new QLabel ( qApp - > translate ( translation_ctx , si . display_name ) , widget_parent ) , current_row , 0 ) ;
2022-08-05 13:52:16 +00:00
layout - > addWidget ( sb , current_row , 1 , 1 , 3 ) ;
current_row + + ;
}
break ;
2022-11-27 08:27:17 +00:00
case SettingInfo : : Type : : IntegerList :
2022-09-12 11:40:25 +00:00
{
QComboBox * cb = new QComboBox ( widget_parent ) ;
cb - > setObjectName ( QString : : fromUtf8 ( si . name ) ) ;
for ( u32 i = 0 ; si . options [ i ] ! = nullptr ; i + + )
2022-12-04 15:00:06 +00:00
cb - > addItem ( qApp - > translate ( translation_ctx , si . options [ i ] ) ) ;
2023-01-30 10:38:23 +00:00
ControllerSettingWidgetBinder : : BindWidgetToInputProfileInt (
2022-12-04 15:00:06 +00:00
sif , cb , m_config_section , std : : move ( key_name ) , si . IntegerDefaultValue ( ) , si . IntegerMinValue ( ) ) ;
layout - > addWidget ( new QLabel ( qApp - > translate ( translation_ctx , si . display_name ) , widget_parent ) , current_row , 0 ) ;
2022-09-12 11:40:25 +00:00
layout - > addWidget ( cb , current_row , 1 , 1 , 3 ) ;
current_row + + ;
}
break ;
2022-11-27 08:27:17 +00:00
case SettingInfo : : Type : : Float :
2022-08-05 13:52:16 +00:00
{
QDoubleSpinBox * sb = new QDoubleSpinBox ( widget_parent ) ;
2022-08-07 06:37:25 +00:00
sb - > setObjectName ( QString : : fromUtf8 ( si . name ) ) ;
2023-01-30 10:38:23 +00:00
sb - > setMinimum ( si . FloatMinValue ( ) * si . multiplier ) ;
sb - > setMaximum ( si . FloatMaxValue ( ) * si . multiplier ) ;
sb - > setSingleStep ( si . FloatStepValue ( ) * si . multiplier ) ;
2022-12-04 15:00:06 +00:00
if ( si . format )
{
2023-10-02 04:46:51 +00:00
const auto [ prefix , suffix , decimals ] = getPrefixAndSuffixForFloatFormat ( qApp - > translate ( translation_ctx , si . format ) ) ;
2022-12-04 15:00:06 +00:00
sb - > setPrefix ( prefix ) ;
if ( decimals > = 0 )
sb - > setDecimals ( decimals ) ;
sb - > setSuffix ( suffix ) ;
}
2023-01-30 10:38:23 +00:00
ControllerSettingWidgetBinder : : BindWidgetToInputProfileFloat (
sif , sb , m_config_section , std : : move ( key_name ) , si . FloatDefaultValue ( ) , si . multiplier ) ;
2022-12-04 15:00:06 +00:00
layout - > addWidget ( new QLabel ( qApp - > translate ( translation_ctx , si . display_name ) , widget_parent ) , current_row , 0 ) ;
2022-08-05 13:52:16 +00:00
layout - > addWidget ( sb , current_row , 1 , 1 , 3 ) ;
current_row + + ;
}
break ;
2022-11-27 08:27:17 +00:00
case SettingInfo : : Type : : String :
2022-08-05 13:52:16 +00:00
{
QLineEdit * le = new QLineEdit ( widget_parent ) ;
2022-08-07 06:37:25 +00:00
le - > setObjectName ( QString : : fromUtf8 ( si . name ) ) ;
2023-01-30 10:38:23 +00:00
ControllerSettingWidgetBinder : : BindWidgetToInputProfileString (
sif , le , m_config_section , std : : move ( key_name ) , si . StringDefaultValue ( ) ) ;
2022-12-04 15:00:06 +00:00
layout - > addWidget ( new QLabel ( qApp - > translate ( translation_ctx , si . display_name ) , widget_parent ) , current_row , 0 ) ;
2022-08-05 13:52:16 +00:00
layout - > addWidget ( le , current_row , 1 , 1 , 3 ) ;
current_row + + ;
}
break ;
2022-12-04 14:55:48 +00:00
case SettingInfo : : Type : : StringList :
{
QComboBox * cb = new QComboBox ( widget_parent ) ;
cb - > setObjectName ( QString : : fromUtf8 ( si . name ) ) ;
if ( si . get_options )
{
std : : vector < std : : pair < std : : string , std : : string > > options ( si . get_options ( ) ) ;
for ( const auto & [ name , display_name ] : options )
cb - > addItem ( QString : : fromStdString ( display_name ) , QString : : fromStdString ( name ) ) ;
}
else if ( si . options )
{
for ( u32 i = 0 ; si . options [ i ] ! = nullptr ; i + + )
2022-12-20 13:21:11 +00:00
cb - > addItem ( qApp - > translate ( translation_ctx , si . options [ i ] ) , QString : : fromUtf8 ( si . options [ i ] ) ) ;
2022-12-04 14:55:48 +00:00
}
2023-01-30 10:38:23 +00:00
ControllerSettingWidgetBinder : : BindWidgetToInputProfileString (
sif , cb , m_config_section , std : : move ( key_name ) , si . StringDefaultValue ( ) ) ;
2022-12-04 15:00:06 +00:00
layout - > addWidget ( new QLabel ( qApp - > translate ( translation_ctx , si . display_name ) , widget_parent ) , current_row , 0 ) ;
2022-12-04 14:55:48 +00:00
layout - > addWidget ( cb , current_row , 1 , 1 , 3 ) ;
current_row + + ;
}
break ;
2022-11-27 08:27:17 +00:00
case SettingInfo : : Type : : Path :
2022-08-05 13:52:16 +00:00
{
QLineEdit * le = new QLineEdit ( widget_parent ) ;
2022-08-07 06:37:25 +00:00
le - > setObjectName ( QString : : fromUtf8 ( si . name ) ) ;
2022-08-05 13:52:16 +00:00
QPushButton * browse_button = new QPushButton ( tr ( " Browse... " ) , widget_parent ) ;
2023-01-30 10:38:23 +00:00
ControllerSettingWidgetBinder : : BindWidgetToInputProfileString (
sif , le , m_config_section , std : : move ( key_name ) , si . StringDefaultValue ( ) ) ;
2022-08-05 13:52:16 +00:00
connect ( browse_button , & QPushButton : : clicked , [ this , le ] ( ) {
2022-12-04 15:00:06 +00:00
const QString path ( QDir : : toNativeSeparators ( QFileDialog : : getOpenFileName ( this , tr ( " Select File " ) ) ) ) ;
2022-08-05 13:52:16 +00:00
if ( ! path . isEmpty ( ) )
le - > setText ( path ) ;
} ) ;
QHBoxLayout * hbox = new QHBoxLayout ( ) ;
hbox - > addWidget ( le , 1 ) ;
hbox - > addWidget ( browse_button ) ;
2022-12-04 15:00:06 +00:00
layout - > addWidget ( new QLabel ( qApp - > translate ( translation_ctx , si . display_name ) , widget_parent ) , current_row , 0 ) ;
2022-08-05 13:52:16 +00:00
layout - > addLayout ( hbox , current_row , 1 , 1 , 3 ) ;
current_row + + ;
}
break ;
}
2022-12-04 15:00:06 +00:00
QLabel * label = new QLabel ( si . description ? qApp - > translate ( translation_ctx , si . description ) : QString ( ) , widget_parent ) ;
2022-08-05 13:52:16 +00:00
label - > setWordWrap ( true ) ;
layout - > addWidget ( label , current_row + + , 0 , 1 , 4 ) ;
layout - > addItem ( new QSpacerItem ( 1 , 10 , QSizePolicy : : Minimum , QSizePolicy : : Fixed ) , current_row + + , 0 , 1 , 4 ) ;
}
2023-01-30 10:24:37 +00:00
QHBoxLayout * bottom_hlayout = new QHBoxLayout ( ) ;
QPushButton * restore_defaults = new QPushButton ( tr ( " Restore Default Settings " ) , this ) ;
restore_defaults - > setIcon ( QIcon : : fromTheme ( QStringLiteral ( " restart-line " ) ) ) ;
connect ( restore_defaults , & QPushButton : : clicked , this , & ControllerCustomSettingsWidget : : restoreDefaults ) ;
bottom_hlayout - > addStretch ( 1 ) ;
bottom_hlayout - > addWidget ( restore_defaults ) ;
layout - > addLayout ( bottom_hlayout , current_row + + , 0 , 1 , 4 ) ;
layout - > addItem ( new QSpacerItem ( 1 , 1 , QSizePolicy : : Minimum , QSizePolicy : : Expanding ) , current_row + + , 0 , 1 , 4 ) ;
2022-08-05 13:52:16 +00:00
}
void ControllerCustomSettingsWidget : : restoreDefaults ( )
{
2022-12-04 15:00:06 +00:00
for ( const SettingInfo & si : m_settings )
2022-08-05 13:52:16 +00:00
{
2022-08-07 06:37:25 +00:00
const QString key ( QString : : fromStdString ( si . name ) ) ;
2022-08-05 13:52:16 +00:00
switch ( si . type )
{
2022-11-27 08:27:17 +00:00
case SettingInfo : : Type : : Boolean :
2022-08-05 13:52:16 +00:00
{
2022-08-07 06:37:25 +00:00
QCheckBox * widget = findChild < QCheckBox * > ( QString : : fromStdString ( si . name ) ) ;
2022-08-05 13:52:16 +00:00
if ( widget )
widget - > setChecked ( si . BooleanDefaultValue ( ) ) ;
}
break ;
2022-11-27 08:27:17 +00:00
case SettingInfo : : Type : : Integer :
2022-08-05 13:52:16 +00:00
{
2022-08-07 06:37:25 +00:00
QSpinBox * widget = findChild < QSpinBox * > ( QString : : fromStdString ( si . name ) ) ;
2022-08-05 13:52:16 +00:00
if ( widget )
widget - > setValue ( si . IntegerDefaultValue ( ) ) ;
}
break ;
2022-11-27 08:27:17 +00:00
case SettingInfo : : Type : : IntegerList :
2022-09-12 11:40:25 +00:00
{
QComboBox * widget = findChild < QComboBox * > ( QString : : fromStdString ( si . name ) ) ;
if ( widget )
widget - > setCurrentIndex ( si . IntegerDefaultValue ( ) - si . IntegerMinValue ( ) ) ;
}
break ;
2022-11-27 08:27:17 +00:00
case SettingInfo : : Type : : Float :
2022-08-05 13:52:16 +00:00
{
2022-08-07 06:37:25 +00:00
QDoubleSpinBox * widget = findChild < QDoubleSpinBox * > ( QString : : fromStdString ( si . name ) ) ;
2022-08-05 13:52:16 +00:00
if ( widget )
2023-01-30 10:38:23 +00:00
widget - > setValue ( si . FloatDefaultValue ( ) * si . multiplier ) ;
2022-08-05 13:52:16 +00:00
}
break ;
2022-11-27 08:27:17 +00:00
case SettingInfo : : Type : : String :
2022-08-05 13:52:16 +00:00
{
2022-08-07 06:37:25 +00:00
QLineEdit * widget = findChild < QLineEdit * > ( QString : : fromStdString ( si . name ) ) ;
2022-08-05 13:52:16 +00:00
if ( widget )
widget - > setText ( QString : : fromUtf8 ( si . StringDefaultValue ( ) ) ) ;
}
break ;
2022-12-04 15:00:06 +00:00
case SettingInfo : : Type : : StringList :
{
QComboBox * widget = findChild < QComboBox * > ( QString : : fromStdString ( si . name ) ) ;
if ( widget )
{
const QString default_value ( QString : : fromUtf8 ( si . StringDefaultValue ( ) ) ) ;
int index = widget - > findData ( default_value ) ;
if ( index < 0 )
index = widget - > findText ( default_value ) ;
if ( index > = 0 )
widget - > setCurrentIndex ( index ) ;
}
}
break ;
2022-11-27 08:27:17 +00:00
case SettingInfo : : Type : : Path :
2022-08-05 13:52:16 +00:00
{
2022-08-07 06:37:25 +00:00
QLineEdit * widget = findChild < QLineEdit * > ( QString : : fromStdString ( si . name ) ) ;
2022-08-05 13:52:16 +00:00
if ( widget )
widget - > setText ( QString : : fromUtf8 ( si . StringDefaultValue ( ) ) ) ;
}
break ;
}
}
}
2021-12-13 12:12:54 +00:00
//////////////////////////////////////////////////////////////////////////
ControllerBindingWidget_Base : : ControllerBindingWidget_Base ( ControllerBindingWidget * parent )
: QWidget ( parent )
{
}
ControllerBindingWidget_Base : : ~ ControllerBindingWidget_Base ( )
{
}
2022-06-08 12:15:10 +00:00
QIcon ControllerBindingWidget_Base : : getIcon ( ) const
{
2023-06-03 08:16:36 +00:00
return QIcon : : fromTheme ( " controller-strike-line " ) ;
2022-06-08 12:15:10 +00:00
}
2021-12-13 12:12:54 +00:00
void ControllerBindingWidget_Base : : initBindingWidgets ( )
{
2023-07-25 15:10:02 +00:00
const Pad : : ControllerInfo * cinfo = Pad : : GetControllerInfo ( getControllerType ( ) ) ;
2022-12-04 15:00:06 +00:00
if ( ! cinfo )
return ;
2021-12-13 12:12:54 +00:00
const std : : string & config_section = getConfigSection ( ) ;
2022-06-08 12:15:10 +00:00
SettingsInterface * sif = getDialog ( ) - > getProfileSettingsInterface ( ) ;
2021-12-13 12:12:54 +00:00
2023-07-25 15:10:02 +00:00
for ( const InputBindingInfo & bi : cinfo - > bindings )
2021-12-13 12:12:54 +00:00
{
2022-12-04 15:00:06 +00:00
if ( bi . bind_type = = InputBindingInfo : : Type : : Axis | | bi . bind_type = = InputBindingInfo : : Type : : HalfAxis | |
bi . bind_type = = InputBindingInfo : : Type : : Button | | bi . bind_type = = InputBindingInfo : : Type : : Pointer | |
bi . bind_type = = InputBindingInfo : : Type : : Device )
2021-12-13 12:12:54 +00:00
{
2022-12-04 15:00:06 +00:00
InputBindingWidget * widget = findChild < InputBindingWidget * > ( QString : : fromStdString ( bi . name ) ) ;
if ( ! widget )
{
Console . Error ( " (ControllerBindingWidget_Base) No widget found for '%s' (%s) " , bi . name , cinfo - > name ) ;
continue ;
}
2021-12-13 12:12:54 +00:00
2022-12-04 15:00:06 +00:00
widget - > initialize ( sif , bi . bind_type , config_section , bi . name ) ;
}
2021-12-13 12:12:54 +00:00
}
2022-12-04 15:00:06 +00:00
switch ( cinfo - > vibration_caps )
2021-12-13 12:12:54 +00:00
{
2023-06-11 06:06:40 +00:00
case Pad : : VibrationCapabilities : : LargeSmallMotors :
2021-12-13 12:12:54 +00:00
{
InputVibrationBindingWidget * widget = findChild < InputVibrationBindingWidget * > ( QStringLiteral ( " LargeMotor " ) ) ;
if ( widget )
widget - > setKey ( getDialog ( ) , config_section , " LargeMotor " ) ;
widget = findChild < InputVibrationBindingWidget * > ( QStringLiteral ( " SmallMotor " ) ) ;
if ( widget )
widget - > setKey ( getDialog ( ) , config_section , " SmallMotor " ) ;
}
break ;
2023-06-11 06:06:40 +00:00
case Pad : : VibrationCapabilities : : SingleMotor :
2021-12-13 12:12:54 +00:00
{
InputVibrationBindingWidget * widget = findChild < InputVibrationBindingWidget * > ( QStringLiteral ( " Motor " ) ) ;
if ( widget )
widget - > setKey ( getDialog ( ) , config_section , " Motor " ) ;
}
break ;
2023-06-11 06:06:40 +00:00
case Pad : : VibrationCapabilities : : NoVibration :
2021-12-13 12:12:54 +00:00
default :
break ;
}
}
ControllerBindingWidget_DualShock2 : : ControllerBindingWidget_DualShock2 ( ControllerBindingWidget * parent )
: ControllerBindingWidget_Base ( parent )
{
m_ui . setupUi ( this ) ;
initBindingWidgets ( ) ;
}
ControllerBindingWidget_DualShock2 : : ~ ControllerBindingWidget_DualShock2 ( )
{
}
2022-06-08 12:15:10 +00:00
QIcon ControllerBindingWidget_DualShock2 : : getIcon ( ) const
{
2023-06-03 08:16:36 +00:00
return QIcon : : fromTheme ( " controller-line " ) ;
2022-06-08 12:15:10 +00:00
}
2021-12-13 12:12:54 +00:00
ControllerBindingWidget_Base * ControllerBindingWidget_DualShock2 : : createInstance ( ControllerBindingWidget * parent )
{
return new ControllerBindingWidget_DualShock2 ( parent ) ;
}
2023-06-11 06:06:40 +00:00
ControllerBindingWidget_Guitar : : ControllerBindingWidget_Guitar ( ControllerBindingWidget * parent )
: ControllerBindingWidget_Base ( parent )
{
m_ui . setupUi ( this ) ;
initBindingWidgets ( ) ;
}
ControllerBindingWidget_Guitar : : ~ ControllerBindingWidget_Guitar ( )
{
}
QIcon ControllerBindingWidget_Guitar : : getIcon ( ) const
{
return QIcon : : fromTheme ( " guitar-line " ) ;
}
ControllerBindingWidget_Base * ControllerBindingWidget_Guitar : : createInstance ( ControllerBindingWidget * parent )
{
return new ControllerBindingWidget_Guitar ( parent ) ;
}
2022-03-20 03:40:47 +00:00
//////////////////////////////////////////////////////////////////////////
2022-12-04 15:00:06 +00:00
2023-10-14 08:45:09 +00:00
USBDeviceWidget : : USBDeviceWidget ( QWidget * parent , ControllerSettingsWindow * dialog , u32 port )
2022-12-04 15:00:06 +00:00
: QWidget ( parent )
, m_dialog ( dialog )
2023-01-30 10:24:37 +00:00
, m_config_section ( fmt : : format ( " USB{} " , port + 1 ) )
2022-12-04 15:00:06 +00:00
, m_port_number ( port )
{
m_ui . setupUi ( this ) ;
2023-01-30 10:24:37 +00:00
m_ui . groupBox - > setTitle ( tr ( " USB Port %1 " ) . arg ( port + 1 ) ) ;
2022-12-04 15:00:06 +00:00
populateDeviceTypes ( ) ;
populatePages ( ) ;
ControllerSettingWidgetBinder : : BindWidgetToInputProfileString (
m_dialog - > getProfileSettingsInterface ( ) , m_ui . deviceType , m_config_section , " Type " , " None " ) ;
connect ( m_ui . deviceType , QOverload < int > : : of ( & QComboBox : : currentIndexChanged ) , this , & USBDeviceWidget : : onTypeChanged ) ;
connect ( m_ui . deviceSubtype , QOverload < int > : : of ( & QComboBox : : currentIndexChanged ) , this , & USBDeviceWidget : : onSubTypeChanged ) ;
connect ( m_ui . bindings , & QPushButton : : clicked , this , & USBDeviceWidget : : onBindingsClicked ) ;
connect ( m_ui . settings , & QPushButton : : clicked , this , & USBDeviceWidget : : onSettingsClicked ) ;
connect ( m_ui . automaticBinding , & QPushButton : : clicked , this , & USBDeviceWidget : : onAutomaticBindingClicked ) ;
connect ( m_ui . clearBindings , & QPushButton : : clicked , this , & USBDeviceWidget : : onClearBindingsClicked ) ;
}
USBDeviceWidget : : ~ USBDeviceWidget ( ) = default ;
QIcon USBDeviceWidget : : getIcon ( ) const
{
2023-08-25 04:19:17 +00:00
static constexpr const char * icons [ ] [ 2 ] = {
{ " Pad " , " wheel-line " } , // Wheel Device
{ " Msd " , " msd-line " } , // Mass Storage Device
{ " singstar " , " singstar-line " } , // Singstar
{ " logitech_usbmic " , " mic-line " } , // Logitech USB Mic
{ " headset " , " headset-line " } , // Logitech Headset Mic
{ " hidkbd " , " keyboard-2-line " } , // HID Keyboard
{ " hidmouse " , " mouse-line " } , // HID Mouse
{ " RBDrumKit " , " drum-line " } , // Rock Band Drum Kit
{ " BuzzDevice " , " buzz-controller-line " } , // Buzz Controller
{ " webcam " , " eyetoy-line " } , // EyeToy
{ " beatmania " , " keyboard-2-line " } , // BeatMania Da Da Da!! (Konami Keyboard)
{ " seamic " , " seamic-line " } , // SEGA Seamic
{ " printer " , " printer-line " } , // Printer
{ " Keyboardmania " , " keyboardmania-line " } , // KeyboardMania
{ " guncon2 " , " guncon2-line " } , // GunCon 2
{ " DJTurntable " , " dj-hero-line " } // DJ Hero TurnTable
} ;
for ( size_t i = 0 ; i < std : : size ( icons ) ; i + + )
{
if ( m_device_type = = icons [ i ] [ 0 ] )
return QIcon : : fromTheme ( icons [ i ] [ 1 ] ) ;
}
2022-12-04 15:00:06 +00:00
return QIcon : : fromTheme ( " usb-fill " ) ;
}
void USBDeviceWidget : : populateDeviceTypes ( )
{
for ( const auto & [ name , display_name ] : USB : : GetDeviceTypes ( ) )
2023-06-19 14:41:21 +00:00
m_ui . deviceType - > addItem ( qApp - > translate ( " USB " , display_name ) , QString : : fromUtf8 ( name ) ) ;
2022-12-04 15:00:06 +00:00
}
void USBDeviceWidget : : populatePages ( )
{
m_device_type = m_dialog - > getStringValue ( m_config_section . c_str ( ) , " Type " , " None " ) ;
m_device_subtype = m_dialog - > getIntValue ( m_config_section . c_str ( ) , fmt : : format ( " {}_subtype " , m_device_type ) . c_str ( ) , 0 ) ;
{
QSignalBlocker sb ( m_ui . deviceSubtype ) ;
m_ui . deviceSubtype - > clear ( ) ;
2022-12-19 10:45:02 +00:00
for ( const char * subtype : USB : : GetDeviceSubtypes ( m_device_type ) )
m_ui . deviceSubtype - > addItem ( qApp - > translate ( " USB " , subtype ) ) ;
2022-12-04 15:00:06 +00:00
m_ui . deviceSubtype - > setCurrentIndex ( m_device_subtype ) ;
m_ui . deviceSubtype - > setVisible ( m_ui . deviceSubtype - > count ( ) > 0 ) ;
}
if ( m_bindings_widget )
{
m_ui . stackedWidget - > removeWidget ( m_bindings_widget ) ;
delete m_bindings_widget ;
m_bindings_widget = nullptr ;
}
if ( m_settings_widget )
{
m_ui . stackedWidget - > removeWidget ( m_settings_widget ) ;
delete m_settings_widget ;
m_settings_widget = nullptr ;
}
2023-07-19 13:53:42 +00:00
const std : : span < const InputBindingInfo > bindings ( USB : : GetDeviceBindings ( m_device_type , m_device_subtype ) ) ;
const std : : span < const SettingInfo > settings ( USB : : GetDeviceSettings ( m_device_type , m_device_subtype ) ) ;
2022-12-04 15:00:06 +00:00
m_ui . bindings - > setEnabled ( ! bindings . empty ( ) ) ;
m_ui . settings - > setEnabled ( ! settings . empty ( ) ) ;
if ( ! bindings . empty ( ) )
{
m_bindings_widget = USBBindingWidget : : createInstance ( m_device_type , m_device_subtype , bindings , this ) ;
if ( m_bindings_widget )
{
m_ui . stackedWidget - > addWidget ( m_bindings_widget ) ;
m_ui . stackedWidget - > setCurrentWidget ( m_bindings_widget ) ;
}
}
if ( ! settings . empty ( ) )
{
m_settings_widget = new ControllerCustomSettingsWidget (
2023-06-19 12:03:10 +00:00
settings , m_config_section , m_device_type + " _ " , " USB " , m_dialog , m_ui . stackedWidget ) ;
2022-12-04 15:00:06 +00:00
m_ui . stackedWidget - > addWidget ( m_settings_widget ) ;
}
updateHeaderToolButtons ( ) ;
}
void USBDeviceWidget : : onTypeChanged ( )
{
populatePages ( ) ;
m_dialog - > updateListDescription ( m_port_number , this ) ;
}
void USBDeviceWidget : : onSubTypeChanged ( int new_index )
{
m_dialog - > setIntValue ( m_config_section . c_str ( ) , fmt : : format ( " {}_subtype " , m_device_type ) . c_str ( ) , new_index ) ;
onTypeChanged ( ) ;
}
void USBDeviceWidget : : updateHeaderToolButtons ( )
{
const QWidget * current_widget = m_ui . stackedWidget - > currentWidget ( ) ;
const QSignalBlocker bindings_sb ( m_ui . bindings ) ;
const QSignalBlocker settings_sb ( m_ui . settings ) ;
const bool is_bindings = ( m_bindings_widget & & current_widget = = m_bindings_widget ) ;
const bool is_settings = ( m_settings_widget & & current_widget = = m_settings_widget ) ;
m_ui . bindings - > setChecked ( is_bindings ) ;
m_ui . automaticBinding - > setEnabled ( is_bindings ) ;
m_ui . clearBindings - > setEnabled ( is_bindings ) ;
m_ui . settings - > setChecked ( is_settings ) ;
}
void USBDeviceWidget : : onBindingsClicked ( )
{
if ( ! m_bindings_widget )
return ;
m_ui . stackedWidget - > setCurrentWidget ( m_bindings_widget ) ;
updateHeaderToolButtons ( ) ;
}
void USBDeviceWidget : : onSettingsClicked ( )
{
if ( ! m_settings_widget )
return ;
m_ui . stackedWidget - > setCurrentWidget ( m_settings_widget ) ;
updateHeaderToolButtons ( ) ;
}
void USBDeviceWidget : : onAutomaticBindingClicked ( )
{
QMenu menu ( this ) ;
bool added = false ;
for ( const QPair < QString , QString > & dev : m_dialog - > getDeviceList ( ) )
{
// we set it as data, because the device list could get invalidated while the menu is up
QAction * action = menu . addAction ( QStringLiteral ( " %1 (%2) " ) . arg ( dev . first ) . arg ( dev . second ) ) ;
action - > setData ( dev . first ) ;
connect ( action , & QAction : : triggered , this , [ this , action ] ( ) { doDeviceAutomaticBinding ( action - > data ( ) . toString ( ) ) ; } ) ;
added = true ;
}
if ( ! added )
{
QAction * action = menu . addAction ( tr ( " No devices available " ) ) ;
action - > setEnabled ( false ) ;
}
menu . exec ( QCursor : : pos ( ) ) ;
}
void USBDeviceWidget : : onClearBindingsClicked ( )
{
if ( QMessageBox : : question ( QtUtils : : GetRootWidget ( this ) , tr ( " Clear Bindings " ) ,
2023-06-30 12:52:41 +00:00
tr ( " Are you sure you want to clear all bindings for this device? This action cannot be undone. " ) ) ! = QMessageBox : : Yes )
2022-12-04 15:00:06 +00:00
{
return ;
}
if ( m_dialog - > isEditingGlobalSettings ( ) )
{
{
auto lock = Host : : GetSettingsLock ( ) ;
USB : : ClearPortBindings ( * Host : : Internal : : GetBaseSettingsLayer ( ) , m_port_number ) ;
}
Host : : CommitBaseSettingChanges ( ) ;
}
else
{
USB : : ClearPortBindings ( * m_dialog - > getProfileSettingsInterface ( ) , m_port_number ) ;
m_dialog - > getProfileSettingsInterface ( ) - > Save ( ) ;
}
// force a refresh after clearing
g_emu_thread - > applySettings ( ) ;
onTypeChanged ( ) ;
}
void USBDeviceWidget : : doDeviceAutomaticBinding ( const QString & device )
{
std : : vector < std : : pair < GenericInputBinding , std : : string > > mapping = InputManager : : GetGenericBindingMapping ( device . toStdString ( ) ) ;
if ( mapping . empty ( ) )
{
QMessageBox : : critical ( QtUtils : : GetRootWidget ( this ) , tr ( " Automatic Binding " ) ,
tr ( " No generic bindings were generated for device '%1'. The controller/source may not support automatic mapping. " ) . arg ( device ) ) ;
return ;
}
bool result ;
if ( m_dialog - > isEditingGlobalSettings ( ) )
{
{
auto lock = Host : : GetSettingsLock ( ) ;
result = USB : : MapDevice ( * Host : : Internal : : GetBaseSettingsLayer ( ) , m_port_number , mapping ) ;
}
if ( result )
Host : : CommitBaseSettingChanges ( ) ;
}
else
{
result = USB : : MapDevice ( * m_dialog - > getProfileSettingsInterface ( ) , m_port_number , mapping ) ;
if ( result )
{
m_dialog - > getProfileSettingsInterface ( ) - > Save ( ) ;
g_emu_thread - > reloadInputBindings ( ) ;
}
}
// force a refresh after mapping
if ( result )
{
g_emu_thread - > applySettings ( ) ;
onTypeChanged ( ) ;
}
}
//////////////////////////////////////////////////////////////////////////
USBBindingWidget : : USBBindingWidget ( USBDeviceWidget * parent )
: QWidget ( parent )
{
}
USBBindingWidget : : ~ USBBindingWidget ( )
{
}
QIcon USBBindingWidget : : getIcon ( ) const
{
2023-06-03 08:16:36 +00:00
return QIcon : : fromTheme ( " controller-strike-line " ) ;
2022-12-04 15:00:06 +00:00
}
std : : string USBBindingWidget : : getBindingKey ( const char * binding_name ) const
{
2022-12-19 10:45:02 +00:00
return USB : : GetConfigSubKey ( getDeviceType ( ) , binding_name ) ;
2022-12-04 15:00:06 +00:00
}
2023-07-19 13:53:42 +00:00
void USBBindingWidget : : createWidgets ( std : : span < const InputBindingInfo > bindings )
2022-12-04 15:00:06 +00:00
{
QGroupBox * axis_gbox = nullptr ;
QGridLayout * axis_layout = nullptr ;
QGroupBox * button_gbox = nullptr ;
QGridLayout * button_layout = nullptr ;
SettingsInterface * sif = getDialog ( ) - > getProfileSettingsInterface ( ) ;
QScrollArea * scrollarea = new QScrollArea ( this ) ;
QWidget * scrollarea_widget = new QWidget ( scrollarea ) ;
scrollarea - > setWidget ( scrollarea_widget ) ;
scrollarea - > setWidgetResizable ( true ) ;
scrollarea - > setFrameShape ( QFrame : : StyledPanel ) ;
scrollarea - > setFrameShadow ( QFrame : : Plain ) ;
// We do axes and buttons separately, so we can figure out how many columns to use.
constexpr int NUM_AXIS_COLUMNS = 2 ;
int column = 0 ;
int row = 0 ;
for ( const InputBindingInfo & bi : bindings )
{
if ( bi . bind_type = = InputBindingInfo : : Type : : Axis | | bi . bind_type = = InputBindingInfo : : Type : : HalfAxis | |
bi . bind_type = = InputBindingInfo : : Type : : Pointer | | bi . bind_type = = InputBindingInfo : : Type : : Device )
{
if ( ! axis_gbox )
{
axis_gbox = new QGroupBox ( tr ( " Axes " ) , scrollarea_widget ) ;
axis_layout = new QGridLayout ( axis_gbox ) ;
}
QGroupBox * gbox = new QGroupBox ( qApp - > translate ( " USB " , bi . display_name ) , axis_gbox ) ;
QVBoxLayout * temp = new QVBoxLayout ( gbox ) ;
InputBindingWidget * widget = new InputBindingWidget ( gbox , sif , bi . bind_type , getConfigSection ( ) , getBindingKey ( bi . name ) ) ;
temp - > addWidget ( widget ) ;
axis_layout - > addWidget ( gbox , row , column ) ;
if ( ( + + column ) = = NUM_AXIS_COLUMNS )
{
column = 0 ;
row + + ;
}
}
}
if ( axis_gbox )
axis_layout - > addItem ( new QSpacerItem ( 1 , 1 , QSizePolicy : : Minimum , QSizePolicy : : Expanding ) , + + row , 0 ) ;
const int num_button_columns = axis_layout ? 2 : 4 ;
row = 0 ;
column = 0 ;
for ( const InputBindingInfo & bi : bindings )
{
if ( bi . bind_type = = InputBindingInfo : : Type : : Button )
{
if ( ! button_gbox )
{
button_gbox = new QGroupBox ( tr ( " Buttons " ) , scrollarea_widget ) ;
button_layout = new QGridLayout ( button_gbox ) ;
}
QGroupBox * gbox = new QGroupBox ( qApp - > translate ( " USB " , bi . display_name ) , button_gbox ) ;
QVBoxLayout * temp = new QVBoxLayout ( gbox ) ;
InputBindingWidget * widget = new InputBindingWidget ( gbox , sif , bi . bind_type , getConfigSection ( ) , getBindingKey ( bi . name ) ) ;
temp - > addWidget ( widget ) ;
button_layout - > addWidget ( gbox , row , column ) ;
if ( ( + + column ) = = num_button_columns )
{
column = 0 ;
row + + ;
}
}
}
if ( button_gbox )
button_layout - > addItem ( new QSpacerItem ( 1 , 1 , QSizePolicy : : Minimum , QSizePolicy : : Expanding ) , + + row , 0 ) ;
if ( ! axis_gbox & & ! button_gbox )
return ;
QHBoxLayout * layout = new QHBoxLayout ( scrollarea_widget ) ;
if ( axis_gbox )
layout - > addWidget ( axis_gbox ) ;
if ( button_gbox )
layout - > addWidget ( button_gbox ) ;
layout - > addItem ( new QSpacerItem ( 1 , 1 , QSizePolicy : : Expanding , QSizePolicy : : Minimum ) ) ;
QHBoxLayout * main_layout = new QHBoxLayout ( this ) ;
main_layout - > addWidget ( scrollarea ) ;
}
2023-07-19 13:53:42 +00:00
void USBBindingWidget : : bindWidgets ( std : : span < const InputBindingInfo > bindings )
2022-12-04 15:00:06 +00:00
{
SettingsInterface * sif = getDialog ( ) - > getProfileSettingsInterface ( ) ;
for ( const InputBindingInfo & bi : bindings )
{
if ( bi . bind_type = = InputBindingInfo : : Type : : Axis | | bi . bind_type = = InputBindingInfo : : Type : : HalfAxis | |
bi . bind_type = = InputBindingInfo : : Type : : Button | | bi . bind_type = = InputBindingInfo : : Type : : Pointer | |
bi . bind_type = = InputBindingInfo : : Type : : Device )
{
InputBindingWidget * widget = findChild < InputBindingWidget * > ( QString : : fromUtf8 ( bi . name ) ) ;
if ( ! widget )
{
Console . Error ( " (USBBindingWidget) No widget found for '%s'. " , bi . name ) ;
continue ;
}
widget - > initialize ( sif , bi . bind_type , getConfigSection ( ) , getBindingKey ( bi . name ) ) ;
}
}
}
USBBindingWidget * USBBindingWidget : : createInstance (
2023-07-19 13:53:42 +00:00
const std : : string & type , u32 subtype , std : : span < const InputBindingInfo > bindings , USBDeviceWidget * parent )
2022-12-04 15:00:06 +00:00
{
USBBindingWidget * widget = new USBBindingWidget ( parent ) ;
bool has_template = false ;
if ( type = = " Pad " )
{
if ( subtype = = 0 ) // Generic or Driving Force
{
Ui : : USBBindingWidget_DrivingForce ( ) . setupUi ( widget ) ;
has_template = true ;
}
else if ( subtype = = 3 ) // GT Force
{
Ui : : USBBindingWidget_GTForce ( ) . setupUi ( widget ) ;
has_template = true ;
}
}
2023-07-23 05:35:32 +00:00
else if ( type = = " guncon2 " )
{
Ui : : USBBindingWidget_GunCon2 ( ) . setupUi ( widget ) ;
has_template = true ;
}
2022-12-04 15:00:06 +00:00
if ( has_template )
widget - > bindWidgets ( bindings ) ;
else
widget - > createWidgets ( bindings ) ;
return widget ;
}