Merge pull request #4597 from Morph1984/mjolnir-p2
Project Mjölnir: Part 2 - Controller Applet
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 4.1 KiB |
After Width: | Height: | Size: 4.4 KiB |
After Width: | Height: | Size: 4.1 KiB |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 4.4 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 2.5 KiB |
|
@ -21,5 +21,35 @@
|
||||||
<file alias="single_joycon_right_vertical">single_joycon_right_vertical.png</file>
|
<file alias="single_joycon_right_vertical">single_joycon_right_vertical.png</file>
|
||||||
<file alias="single_joycon_right_vertical_dark">single_joycon_right_vertical_dark.png</file>
|
<file alias="single_joycon_right_vertical_dark">single_joycon_right_vertical_dark.png</file>
|
||||||
<file alias="single_joycon_right_vertical_midnight">single_joycon_right_vertical_midnight.png</file>
|
<file alias="single_joycon_right_vertical_midnight">single_joycon_right_vertical_midnight.png</file>
|
||||||
|
<file alias="applet_dual_joycon">applet_dual_joycon.png</file>
|
||||||
|
<file alias="applet_dual_joycon_dark">applet_dual_joycon_dark.png</file>
|
||||||
|
<file alias="applet_dual_joycon_midnight">applet_dual_joycon_midnight.png</file>
|
||||||
|
<file alias="applet_handheld">applet_handheld.png</file>
|
||||||
|
<file alias="applet_handheld_dark">applet_handheld_dark.png</file>
|
||||||
|
<file alias="applet_handheld_midnight">applet_handheld_midnight.png</file>
|
||||||
|
<file alias="applet_pro_controller">applet_pro_controller.png</file>
|
||||||
|
<file alias="applet_pro_controller_dark">applet_pro_controller_dark.png</file>
|
||||||
|
<file alias="applet_pro_controller_midnight">applet_pro_controller_midnight.png</file>
|
||||||
|
<file alias="applet_joycon_left">applet_single_joycon_left.png</file>
|
||||||
|
<file alias="applet_joycon_left_dark">applet_single_joycon_left_dark.png</file>
|
||||||
|
<file alias="applet_joycon_left_midnight">applet_single_joycon_left_midnight.png</file>
|
||||||
|
<file alias="applet_joycon_right">applet_single_joycon_right.png</file>
|
||||||
|
<file alias="applet_joycon_right_dark">applet_single_joycon_right_dark.png</file>
|
||||||
|
<file alias="applet_joycon_right_midnight">applet_single_joycon_right_midnight.png</file>
|
||||||
|
<file alias="applet_dual_joycon_disabled">applet_dual_joycon_disabled.png</file>
|
||||||
|
<file alias="applet_dual_joycon_dark_disabled">applet_dual_joycon_dark_disabled.png</file>
|
||||||
|
<file alias="applet_dual_joycon_midnight_disabled">applet_dual_joycon_midnight_disabled.png</file>
|
||||||
|
<file alias="applet_handheld_disabled">applet_handheld_disabled.png</file>
|
||||||
|
<file alias="applet_handheld_dark_disabled">applet_handheld_dark_disabled.png</file>
|
||||||
|
<file alias="applet_handheld_midnight_disabled">applet_handheld_midnight_disabled.png</file>
|
||||||
|
<file alias="applet_pro_controller_disabled">applet_pro_controller_disabled.png</file>
|
||||||
|
<file alias="applet_pro_controller_dark_disabled">applet_pro_controller_dark_disabled.png</file>
|
||||||
|
<file alias="applet_pro_controller_midnight_disabled">applet_pro_controller_midnight_disabled.png</file>
|
||||||
|
<file alias="applet_joycon_left_disabled">applet_single_joycon_left_disabled.png</file>
|
||||||
|
<file alias="applet_joycon_left_dark_disabled">applet_single_joycon_left_dark_disabled.png</file>
|
||||||
|
<file alias="applet_joycon_left_midnight_disabled">applet_single_joycon_left_midnight_disabled.png</file>
|
||||||
|
<file alias="applet_joycon_right_disabled">applet_single_joycon_right_disabled.png</file>
|
||||||
|
<file alias="applet_joycon_right_dark_disabled">applet_single_joycon_right_dark_disabled.png</file>
|
||||||
|
<file alias="applet_joycon_right_midnight_disabled">applet_single_joycon_right_midnight_disabled.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|
|
@ -41,6 +41,99 @@ QPushButton#buttonRefreshDevices {
|
||||||
max-height: 20px;
|
max-height: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QWidget#bottomPerGameInput,
|
||||||
|
QWidget#topControllerApplet,
|
||||||
|
QWidget#bottomControllerApplet,
|
||||||
|
QGroupBox#groupPlayer1Connected:checked,
|
||||||
|
QGroupBox#groupPlayer2Connected:checked,
|
||||||
|
QGroupBox#groupPlayer3Connected:checked,
|
||||||
|
QGroupBox#groupPlayer4Connected:checked,
|
||||||
|
QGroupBox#groupPlayer5Connected:checked,
|
||||||
|
QGroupBox#groupPlayer6Connected:checked,
|
||||||
|
QGroupBox#groupPlayer7Connected:checked,
|
||||||
|
QGroupBox#groupPlayer8Connected:checked {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget#topControllerApplet {
|
||||||
|
border-bottom: 1px solid #828790
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget#bottomPerGameInput,
|
||||||
|
QWidget#bottomControllerApplet {
|
||||||
|
border-top: 1px solid #828790
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget#topPerGameInput,
|
||||||
|
QWidget#middleControllerApplet {
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget#topPerGameInput QComboBox,
|
||||||
|
QWidget#middleControllerApplet QComboBox {
|
||||||
|
width: 123px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget#connectedControllers {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget#playersSupported,
|
||||||
|
QWidget#controllersSupported,
|
||||||
|
QWidget#controllerSupported1,
|
||||||
|
QWidget#controllerSupported2,
|
||||||
|
QWidget#controllerSupported3,
|
||||||
|
QWidget#controllerSupported4,
|
||||||
|
QWidget#controllerSupported5,
|
||||||
|
QWidget#controllerSupported6 {
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
QGroupBox#groupPlayer1Connected,
|
||||||
|
QGroupBox#groupPlayer2Connected,
|
||||||
|
QGroupBox#groupPlayer3Connected,
|
||||||
|
QGroupBox#groupPlayer4Connected,
|
||||||
|
QGroupBox#groupPlayer5Connected,
|
||||||
|
QGroupBox#groupPlayer6Connected,
|
||||||
|
QGroupBox#groupPlayer7Connected,
|
||||||
|
QGroupBox#groupPlayer8Connected {
|
||||||
|
border: 1px solid #828790;
|
||||||
|
border-radius: 3px;
|
||||||
|
padding: 0px;
|
||||||
|
min-height: 98px;
|
||||||
|
max-height: 98px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QGroupBox#groupPlayer1Connected:unchecked,
|
||||||
|
QGroupBox#groupPlayer2Connected:unchecked,
|
||||||
|
QGroupBox#groupPlayer3Connected:unchecked,
|
||||||
|
QGroupBox#groupPlayer4Connected:unchecked,
|
||||||
|
QGroupBox#groupPlayer5Connected:unchecked,
|
||||||
|
QGroupBox#groupPlayer6Connected:unchecked,
|
||||||
|
QGroupBox#groupPlayer7Connected:unchecked,
|
||||||
|
QGroupBox#groupPlayer8Connected:unchecked {
|
||||||
|
border: 1px solid #d9d9d9;
|
||||||
|
}
|
||||||
|
|
||||||
|
QGroupBox#groupPlayer1Connected::title,
|
||||||
|
QGroupBox#groupPlayer2Connected::title,
|
||||||
|
QGroupBox#groupPlayer3Connected::title,
|
||||||
|
QGroupBox#groupPlayer4Connected::title,
|
||||||
|
QGroupBox#groupPlayer5Connected::title,
|
||||||
|
QGroupBox#groupPlayer6Connected::title,
|
||||||
|
QGroupBox#groupPlayer7Connected::title,
|
||||||
|
QGroupBox#groupPlayer8Connected::title {
|
||||||
|
subcontrol-origin: margin;
|
||||||
|
subcontrol-position: top left;
|
||||||
|
padding-left: 0px;
|
||||||
|
padding-right: 0px;
|
||||||
|
padding-top: 1px;
|
||||||
|
margin-left: 0px;
|
||||||
|
margin-right: -4px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
QCheckBox#checkboxPlayer1Connected,
|
QCheckBox#checkboxPlayer1Connected,
|
||||||
QCheckBox#checkboxPlayer2Connected,
|
QCheckBox#checkboxPlayer2Connected,
|
||||||
QCheckBox#checkboxPlayer3Connected,
|
QCheckBox#checkboxPlayer3Connected,
|
||||||
|
@ -52,6 +145,42 @@ QCheckBox#checkboxPlayer8Connected {
|
||||||
spacing: 0px;
|
spacing: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QWidget#Player1LEDs QCheckBox,
|
||||||
|
QWidget#Player2LEDs QCheckBox,
|
||||||
|
QWidget#Player3LEDs QCheckBox,
|
||||||
|
QWidget#Player4LEDs QCheckBox,
|
||||||
|
QWidget#Player5LEDs QCheckBox,
|
||||||
|
QWidget#Player6LEDs QCheckBox,
|
||||||
|
QWidget#Player7LEDs QCheckBox,
|
||||||
|
QWidget#Player8LEDs QCheckBox {
|
||||||
|
spacing: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget#Player1LEDs QCheckBox::indicator,
|
||||||
|
QWidget#Player2LEDs QCheckBox::indicator,
|
||||||
|
QWidget#Player3LEDs QCheckBox::indicator,
|
||||||
|
QWidget#Player4LEDs QCheckBox::indicator,
|
||||||
|
QWidget#Player5LEDs QCheckBox::indicator,
|
||||||
|
QWidget#Player6LEDs QCheckBox::indicator,
|
||||||
|
QWidget#Player7LEDs QCheckBox::indicator,
|
||||||
|
QWidget#Player8LEDs QCheckBox::indicator {
|
||||||
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
|
margin-left: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer1Connected::indicator,
|
||||||
|
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer2Connected::indicator,
|
||||||
|
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer3Connected::indicator,
|
||||||
|
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer4Connected::indicator,
|
||||||
|
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer5Connected::indicator,
|
||||||
|
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer6Connected::indicator,
|
||||||
|
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer7Connected::indicator,
|
||||||
|
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer8Connected::indicator {
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
QCheckBox#checkboxPlayer1Connected::indicator,
|
QCheckBox#checkboxPlayer1Connected::indicator,
|
||||||
QCheckBox#checkboxPlayer2Connected::indicator,
|
QCheckBox#checkboxPlayer2Connected::indicator,
|
||||||
QCheckBox#checkboxPlayer3Connected::indicator,
|
QCheckBox#checkboxPlayer3Connected::indicator,
|
||||||
|
@ -64,6 +193,34 @@ QCheckBox#checkboxPlayer8Connected::indicator {
|
||||||
height: 14px;
|
height: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QGroupBox#groupPlayer1Connected::indicator,
|
||||||
|
QGroupBox#groupPlayer2Connected::indicator,
|
||||||
|
QGroupBox#groupPlayer3Connected::indicator,
|
||||||
|
QGroupBox#groupPlayer4Connected::indicator,
|
||||||
|
QGroupBox#groupPlayer5Connected::indicator,
|
||||||
|
QGroupBox#groupPlayer6Connected::indicator,
|
||||||
|
QGroupBox#groupPlayer7Connected::indicator,
|
||||||
|
QGroupBox#groupPlayer8Connected::indicator {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget#Player1LEDs QCheckBox::indicator:checked,
|
||||||
|
QWidget#Player2LEDs QCheckBox::indicator:checked,
|
||||||
|
QWidget#Player3LEDs QCheckBox::indicator:checked,
|
||||||
|
QWidget#Player4LEDs QCheckBox::indicator:checked,
|
||||||
|
QWidget#Player5LEDs QCheckBox::indicator:checked,
|
||||||
|
QWidget#Player6LEDs QCheckBox::indicator:checked,
|
||||||
|
QWidget#Player7LEDs QCheckBox::indicator:checked,
|
||||||
|
QWidget#Player8LEDs QCheckBox::indicator:checked,
|
||||||
|
QGroupBox#groupPlayer1Connected::indicator:checked,
|
||||||
|
QGroupBox#groupPlayer2Connected::indicator:checked,
|
||||||
|
QGroupBox#groupPlayer3Connected::indicator:checked,
|
||||||
|
QGroupBox#groupPlayer4Connected::indicator:checked,
|
||||||
|
QGroupBox#groupPlayer5Connected::indicator:checked,
|
||||||
|
QGroupBox#groupPlayer6Connected::indicator:checked,
|
||||||
|
QGroupBox#groupPlayer7Connected::indicator:checked,
|
||||||
|
QGroupBox#groupPlayer8Connected::indicator:checked,
|
||||||
QCheckBox#checkboxPlayer1Connected::indicator:checked,
|
QCheckBox#checkboxPlayer1Connected::indicator:checked,
|
||||||
QCheckBox#checkboxPlayer2Connected::indicator:checked,
|
QCheckBox#checkboxPlayer2Connected::indicator:checked,
|
||||||
QCheckBox#checkboxPlayer3Connected::indicator:checked,
|
QCheckBox#checkboxPlayer3Connected::indicator:checked,
|
||||||
|
@ -74,11 +231,27 @@ QCheckBox#checkboxPlayer7Connected::indicator:checked,
|
||||||
QCheckBox#checkboxPlayer8Connected::indicator:checked,
|
QCheckBox#checkboxPlayer8Connected::indicator:checked,
|
||||||
QGroupBox#groupConnectedController::indicator:checked {
|
QGroupBox#groupConnectedController::indicator:checked {
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
border: 1px solid black;
|
border: 1px solid #929192;
|
||||||
background: #39ff14;
|
background: #39ff14;
|
||||||
image: none;
|
image: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QWidget#Player1LEDs QCheckBox::indicator:unchecked,
|
||||||
|
QWidget#Player2LEDs QCheckBox::indicator:unchecked,
|
||||||
|
QWidget#Player3LEDs QCheckBox::indicator:unchecked,
|
||||||
|
QWidget#Player4LEDs QCheckBox::indicator:unchecked,
|
||||||
|
QWidget#Player5LEDs QCheckBox::indicator:unchecked,
|
||||||
|
QWidget#Player6LEDs QCheckBox::indicator:unchecked,
|
||||||
|
QWidget#Player7LEDs QCheckBox::indicator:unchecked,
|
||||||
|
QWidget#Player8LEDs QCheckBox::indicator:unchecked,
|
||||||
|
QGroupBox#groupPlayer1Connected::indicator:unchecked,
|
||||||
|
QGroupBox#groupPlayer2Connected::indicator:unchecked,
|
||||||
|
QGroupBox#groupPlayer3Connected::indicator:unchecked,
|
||||||
|
QGroupBox#groupPlayer4Connected::indicator:unchecked,
|
||||||
|
QGroupBox#groupPlayer5Connected::indicator:unchecked,
|
||||||
|
QGroupBox#groupPlayer6Connected::indicator:unchecked,
|
||||||
|
QGroupBox#groupPlayer7Connected::indicator:unchecked,
|
||||||
|
QGroupBox#groupPlayer8Connected::indicator:unchecked,
|
||||||
QCheckBox#checkboxPlayer1Connected::indicator:unchecked,
|
QCheckBox#checkboxPlayer1Connected::indicator:unchecked,
|
||||||
QCheckBox#checkboxPlayer2Connected::indicator:unchecked,
|
QCheckBox#checkboxPlayer2Connected::indicator:unchecked,
|
||||||
QCheckBox#checkboxPlayer3Connected::indicator:unchecked,
|
QCheckBox#checkboxPlayer3Connected::indicator:unchecked,
|
||||||
|
@ -89,7 +262,18 @@ QCheckBox#checkboxPlayer7Connected::indicator:unchecked,
|
||||||
QCheckBox#checkboxPlayer8Connected::indicator:unchecked,
|
QCheckBox#checkboxPlayer8Connected::indicator:unchecked,
|
||||||
QGroupBox#groupConnectedController::indicator:unchecked {
|
QGroupBox#groupConnectedController::indicator:unchecked {
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
border: 1px solid black;
|
border: 1px solid #929192;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
image: none;
|
image: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QWidget#controllerPlayer1,
|
||||||
|
QWidget#controllerPlayer2,
|
||||||
|
QWidget#controllerPlayer3,
|
||||||
|
QWidget#controllerPlayer4,
|
||||||
|
QWidget#controllerPlayer5,
|
||||||
|
QWidget#controllerPlayer6,
|
||||||
|
QWidget#controllerPlayer7,
|
||||||
|
QWidget#controllerPlayer8 {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
|
@ -52,6 +52,6 @@
|
||||||
<file>rc/radio_unchecked.png</file>
|
<file>rc/radio_unchecked.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
<qresource prefix="qdarkstyle">
|
<qresource prefix="qdarkstyle">
|
||||||
<file>style.qss</file>
|
<file>style.qss</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|
|
@ -1284,59 +1284,6 @@ QPushButton#buttonRefreshDevices {
|
||||||
padding: 0px 0px;
|
padding: 0px 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
QCheckBox#checkboxPlayer1Connected,
|
|
||||||
QCheckBox#checkboxPlayer2Connected,
|
|
||||||
QCheckBox#checkboxPlayer3Connected,
|
|
||||||
QCheckBox#checkboxPlayer4Connected,
|
|
||||||
QCheckBox#checkboxPlayer5Connected,
|
|
||||||
QCheckBox#checkboxPlayer6Connected,
|
|
||||||
QCheckBox#checkboxPlayer7Connected,
|
|
||||||
QCheckBox#checkboxPlayer8Connected {
|
|
||||||
spacing: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
QCheckBox#checkboxPlayer1Connected::indicator,
|
|
||||||
QCheckBox#checkboxPlayer2Connected::indicator,
|
|
||||||
QCheckBox#checkboxPlayer3Connected::indicator,
|
|
||||||
QCheckBox#checkboxPlayer4Connected::indicator,
|
|
||||||
QCheckBox#checkboxPlayer5Connected::indicator,
|
|
||||||
QCheckBox#checkboxPlayer6Connected::indicator,
|
|
||||||
QCheckBox#checkboxPlayer7Connected::indicator,
|
|
||||||
QCheckBox#checkboxPlayer8Connected::indicator {
|
|
||||||
width: 14px;
|
|
||||||
height: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
QCheckBox#checkboxPlayer1Connected::indicator:checked,
|
|
||||||
QCheckBox#checkboxPlayer2Connected::indicator:checked,
|
|
||||||
QCheckBox#checkboxPlayer3Connected::indicator:checked,
|
|
||||||
QCheckBox#checkboxPlayer4Connected::indicator:checked,
|
|
||||||
QCheckBox#checkboxPlayer5Connected::indicator:checked,
|
|
||||||
QCheckBox#checkboxPlayer6Connected::indicator:checked,
|
|
||||||
QCheckBox#checkboxPlayer7Connected::indicator:checked,
|
|
||||||
QCheckBox#checkboxPlayer8Connected::indicator:checked,
|
|
||||||
QGroupBox#groupConnectedController::indicator:checked {
|
|
||||||
border-radius: 2px;
|
|
||||||
border: 1px solid #929192;
|
|
||||||
background: #39ff14;
|
|
||||||
image: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
QCheckBox#checkboxPlayer1Connected::indicator:unchecked,
|
|
||||||
QCheckBox#checkboxPlayer2Connected::indicator:unchecked,
|
|
||||||
QCheckBox#checkboxPlayer3Connected::indicator:unchecked,
|
|
||||||
QCheckBox#checkboxPlayer4Connected::indicator:unchecked,
|
|
||||||
QCheckBox#checkboxPlayer5Connected::indicator:unchecked,
|
|
||||||
QCheckBox#checkboxPlayer6Connected::indicator:unchecked,
|
|
||||||
QCheckBox#checkboxPlayer7Connected::indicator:unchecked,
|
|
||||||
QCheckBox#checkboxPlayer8Connected::indicator:unchecked,
|
|
||||||
QGroupBox#groupConnectedController::indicator:unchecked {
|
|
||||||
border-radius: 2px;
|
|
||||||
border: 1px solid #929192;
|
|
||||||
background: transparent;
|
|
||||||
image: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
QSpinBox#spinboxLStickRange,
|
QSpinBox#spinboxLStickRange,
|
||||||
QSpinBox#spinboxRStickRange {
|
QSpinBox#spinboxRStickRange {
|
||||||
padding: 4px 0px 5px 0px;
|
padding: 4px 0px 5px 0px;
|
||||||
|
@ -1367,9 +1314,260 @@ QGroupBox#vibrationGroup::indicator {
|
||||||
|
|
||||||
QGroupBox#motionGroup::title,
|
QGroupBox#motionGroup::title,
|
||||||
QGroupBox#vibrationGroup::title {
|
QGroupBox#vibrationGroup::title {
|
||||||
spacing: 2px;
|
spacing: 2px;
|
||||||
padding-left: 1px;
|
padding-left: 1px;
|
||||||
padding-right: 1px;
|
padding-right: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget#bottomPerGameInput,
|
||||||
|
QWidget#topControllerApplet,
|
||||||
|
QWidget#bottomControllerApplet,
|
||||||
|
QGroupBox#groupPlayer1Connected:checked,
|
||||||
|
QGroupBox#groupPlayer2Connected:checked,
|
||||||
|
QGroupBox#groupPlayer3Connected:checked,
|
||||||
|
QGroupBox#groupPlayer4Connected:checked,
|
||||||
|
QGroupBox#groupPlayer5Connected:checked,
|
||||||
|
QGroupBox#groupPlayer6Connected:checked,
|
||||||
|
QGroupBox#groupPlayer7Connected:checked,
|
||||||
|
QGroupBox#groupPlayer8Connected:checked {
|
||||||
|
background-color: #232629;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget#topPerGameInput,
|
||||||
|
QWidget#middleControllerApplet {
|
||||||
|
background-color: #31363b;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget#topPerGameInput QComboBox,
|
||||||
|
QWidget#middleControllerApplet QComboBox {
|
||||||
|
width: 119px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRadioButton#radioDocked {
|
||||||
|
margin-left: -3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QRadioButton#radioUndocked {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget#connectedControllers {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget#playersSupported,
|
||||||
|
QWidget#controllersSupported,
|
||||||
|
QWidget#controllerSupported1,
|
||||||
|
QWidget#controllerSupported2,
|
||||||
|
QWidget#controllerSupported3,
|
||||||
|
QWidget#controllerSupported4,
|
||||||
|
QWidget#controllerSupported5,
|
||||||
|
QWidget#controllerSupported6 {
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
QGroupBox#groupPlayer1Connected,
|
||||||
|
QGroupBox#groupPlayer2Connected,
|
||||||
|
QGroupBox#groupPlayer3Connected,
|
||||||
|
QGroupBox#groupPlayer4Connected,
|
||||||
|
QGroupBox#groupPlayer5Connected,
|
||||||
|
QGroupBox#groupPlayer6Connected,
|
||||||
|
QGroupBox#groupPlayer7Connected,
|
||||||
|
QGroupBox#groupPlayer8Connected {
|
||||||
|
border: 1px solid #76797c;
|
||||||
|
border-radius: 3px;
|
||||||
|
padding: 0px;
|
||||||
|
min-height: 98px;
|
||||||
|
max-height: 98px;
|
||||||
|
margin-top: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QGroupBox#groupPlayer1Connected:unchecked,
|
||||||
|
QGroupBox#groupPlayer2Connected:unchecked,
|
||||||
|
QGroupBox#groupPlayer3Connected:unchecked,
|
||||||
|
QGroupBox#groupPlayer4Connected:unchecked,
|
||||||
|
QGroupBox#groupPlayer5Connected:unchecked,
|
||||||
|
QGroupBox#groupPlayer6Connected:unchecked,
|
||||||
|
QGroupBox#groupPlayer7Connected:unchecked,
|
||||||
|
QGroupBox#groupPlayer8Connected:unchecked {
|
||||||
|
border: 1px solid #54575b;
|
||||||
|
}
|
||||||
|
|
||||||
|
QGroupBox#groupPlayer1Connected::title,
|
||||||
|
QGroupBox#groupPlayer2Connected::title,
|
||||||
|
QGroupBox#groupPlayer3Connected::title,
|
||||||
|
QGroupBox#groupPlayer4Connected::title,
|
||||||
|
QGroupBox#groupPlayer5Connected::title,
|
||||||
|
QGroupBox#groupPlayer6Connected::title,
|
||||||
|
QGroupBox#groupPlayer7Connected::title,
|
||||||
|
QGroupBox#groupPlayer8Connected::title {
|
||||||
|
subcontrol-origin: margin;
|
||||||
|
subcontrol-position: top left;
|
||||||
|
padding-left: 0px;
|
||||||
|
padding-right: 0px;
|
||||||
|
padding-top: 1px;
|
||||||
|
margin-left: -2px;
|
||||||
|
margin-right: -4px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QCheckBox#checkboxPlayer1Connected,
|
||||||
|
QCheckBox#checkboxPlayer2Connected,
|
||||||
|
QCheckBox#checkboxPlayer3Connected,
|
||||||
|
QCheckBox#checkboxPlayer4Connected,
|
||||||
|
QCheckBox#checkboxPlayer5Connected,
|
||||||
|
QCheckBox#checkboxPlayer6Connected,
|
||||||
|
QCheckBox#checkboxPlayer7Connected,
|
||||||
|
QCheckBox#checkboxPlayer8Connected {
|
||||||
|
spacing: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget#Player1LEDs,
|
||||||
|
QWidget#Player2LEDs,
|
||||||
|
QWidget#Player3LEDs,
|
||||||
|
QWidget#Player4LEDs,
|
||||||
|
QWidget#Player5LEDs,
|
||||||
|
QWidget#Player6LEDs,
|
||||||
|
QWidget#Player7LEDs,
|
||||||
|
QWidget#Player8LEDs {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget#Player1LEDs QCheckBox,
|
||||||
|
QWidget#Player2LEDs QCheckBox,
|
||||||
|
QWidget#Player3LEDs QCheckBox,
|
||||||
|
QWidget#Player4LEDs QCheckBox,
|
||||||
|
QWidget#Player5LEDs QCheckBox,
|
||||||
|
QWidget#Player6LEDs QCheckBox,
|
||||||
|
QWidget#Player7LEDs QCheckBox,
|
||||||
|
QWidget#Player8LEDs QCheckBox {
|
||||||
|
spacing: 0px;
|
||||||
|
margin-bottom: 0px;
|
||||||
|
margin-right: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget#Player1LEDs QCheckBox::indicator,
|
||||||
|
QWidget#Player2LEDs QCheckBox::indicator,
|
||||||
|
QWidget#Player3LEDs QCheckBox::indicator,
|
||||||
|
QWidget#Player4LEDs QCheckBox::indicator,
|
||||||
|
QWidget#Player5LEDs QCheckBox::indicator,
|
||||||
|
QWidget#Player6LEDs QCheckBox::indicator,
|
||||||
|
QWidget#Player7LEDs QCheckBox::indicator,
|
||||||
|
QWidget#Player8LEDs QCheckBox::indicator {
|
||||||
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
|
margin-left: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer1Connected::indicator,
|
||||||
|
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer2Connected::indicator,
|
||||||
|
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer3Connected::indicator,
|
||||||
|
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer4Connected::indicator,
|
||||||
|
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer5Connected::indicator,
|
||||||
|
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer6Connected::indicator,
|
||||||
|
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer7Connected::indicator,
|
||||||
|
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer8Connected::indicator {
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QCheckBox#checkboxPlayer1Connected::indicator,
|
||||||
|
QCheckBox#checkboxPlayer2Connected::indicator,
|
||||||
|
QCheckBox#checkboxPlayer3Connected::indicator,
|
||||||
|
QCheckBox#checkboxPlayer4Connected::indicator,
|
||||||
|
QCheckBox#checkboxPlayer5Connected::indicator,
|
||||||
|
QCheckBox#checkboxPlayer6Connected::indicator,
|
||||||
|
QCheckBox#checkboxPlayer7Connected::indicator,
|
||||||
|
QCheckBox#checkboxPlayer8Connected::indicator {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QGroupBox#groupPlayer1Connected::indicator,
|
||||||
|
QGroupBox#groupPlayer2Connected::indicator,
|
||||||
|
QGroupBox#groupPlayer3Connected::indicator,
|
||||||
|
QGroupBox#groupPlayer4Connected::indicator,
|
||||||
|
QGroupBox#groupPlayer5Connected::indicator,
|
||||||
|
QGroupBox#groupPlayer6Connected::indicator,
|
||||||
|
QGroupBox#groupPlayer7Connected::indicator,
|
||||||
|
QGroupBox#groupPlayer8Connected::indicator {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget#Player1LEDs QCheckBox::indicator:checked,
|
||||||
|
QWidget#Player2LEDs QCheckBox::indicator:checked,
|
||||||
|
QWidget#Player3LEDs QCheckBox::indicator:checked,
|
||||||
|
QWidget#Player4LEDs QCheckBox::indicator:checked,
|
||||||
|
QWidget#Player5LEDs QCheckBox::indicator:checked,
|
||||||
|
QWidget#Player6LEDs QCheckBox::indicator:checked,
|
||||||
|
QWidget#Player7LEDs QCheckBox::indicator:checked,
|
||||||
|
QWidget#Player8LEDs QCheckBox::indicator:checked,
|
||||||
|
QGroupBox#groupPlayer1Connected::indicator:checked,
|
||||||
|
QGroupBox#groupPlayer2Connected::indicator:checked,
|
||||||
|
QGroupBox#groupPlayer3Connected::indicator:checked,
|
||||||
|
QGroupBox#groupPlayer4Connected::indicator:checked,
|
||||||
|
QGroupBox#groupPlayer5Connected::indicator:checked,
|
||||||
|
QGroupBox#groupPlayer6Connected::indicator:checked,
|
||||||
|
QGroupBox#groupPlayer7Connected::indicator:checked,
|
||||||
|
QGroupBox#groupPlayer8Connected::indicator:checked,
|
||||||
|
QCheckBox#checkboxPlayer1Connected::indicator:checked,
|
||||||
|
QCheckBox#checkboxPlayer2Connected::indicator:checked,
|
||||||
|
QCheckBox#checkboxPlayer3Connected::indicator:checked,
|
||||||
|
QCheckBox#checkboxPlayer4Connected::indicator:checked,
|
||||||
|
QCheckBox#checkboxPlayer5Connected::indicator:checked,
|
||||||
|
QCheckBox#checkboxPlayer6Connected::indicator:checked,
|
||||||
|
QCheckBox#checkboxPlayer7Connected::indicator:checked,
|
||||||
|
QCheckBox#checkboxPlayer8Connected::indicator:checked,
|
||||||
|
QGroupBox#groupConnectedController::indicator:checked {
|
||||||
|
border-radius: 2px;
|
||||||
|
border: 1px solid #929192;
|
||||||
|
background: #39ff14;
|
||||||
|
image: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget#Player1LEDs QCheckBox::indicator:unchecked,
|
||||||
|
QWidget#Player2LEDs QCheckBox::indicator:unchecked,
|
||||||
|
QWidget#Player3LEDs QCheckBox::indicator:unchecked,
|
||||||
|
QWidget#Player4LEDs QCheckBox::indicator:unchecked,
|
||||||
|
QWidget#Player5LEDs QCheckBox::indicator:unchecked,
|
||||||
|
QWidget#Player6LEDs QCheckBox::indicator:unchecked,
|
||||||
|
QWidget#Player7LEDs QCheckBox::indicator:unchecked,
|
||||||
|
QWidget#Player8LEDs QCheckBox::indicator:unchecked,
|
||||||
|
QGroupBox#groupPlayer1Connected::indicator:unchecked,
|
||||||
|
QGroupBox#groupPlayer2Connected::indicator:unchecked,
|
||||||
|
QGroupBox#groupPlayer3Connected::indicator:unchecked,
|
||||||
|
QGroupBox#groupPlayer4Connected::indicator:unchecked,
|
||||||
|
QGroupBox#groupPlayer5Connected::indicator:unchecked,
|
||||||
|
QGroupBox#groupPlayer6Connected::indicator:unchecked,
|
||||||
|
QGroupBox#groupPlayer7Connected::indicator:unchecked,
|
||||||
|
QGroupBox#groupPlayer8Connected::indicator:unchecked,
|
||||||
|
QCheckBox#checkboxPlayer1Connected::indicator:unchecked,
|
||||||
|
QCheckBox#checkboxPlayer2Connected::indicator:unchecked,
|
||||||
|
QCheckBox#checkboxPlayer3Connected::indicator:unchecked,
|
||||||
|
QCheckBox#checkboxPlayer4Connected::indicator:unchecked,
|
||||||
|
QCheckBox#checkboxPlayer5Connected::indicator:unchecked,
|
||||||
|
QCheckBox#checkboxPlayer6Connected::indicator:unchecked,
|
||||||
|
QCheckBox#checkboxPlayer7Connected::indicator:unchecked,
|
||||||
|
QCheckBox#checkboxPlayer8Connected::indicator:unchecked,
|
||||||
|
QGroupBox#groupConnectedController::indicator:unchecked {
|
||||||
|
border-radius: 2px;
|
||||||
|
border: 1px solid #929192;
|
||||||
|
background: transparent;
|
||||||
|
image: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget#controllerPlayer1,
|
||||||
|
QWidget#controllerPlayer2,
|
||||||
|
QWidget#controllerPlayer3,
|
||||||
|
QWidget#controllerPlayer4,
|
||||||
|
QWidget#controllerPlayer5,
|
||||||
|
QWidget#controllerPlayer6,
|
||||||
|
QWidget#controllerPlayer7,
|
||||||
|
QWidget#controllerPlayer8 {
|
||||||
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* touchscreen mapping widget */
|
/* touchscreen mapping widget */
|
||||||
|
|
|
@ -221,6 +221,6 @@
|
||||||
<file>rc/window_undock_pressed@2x.png</file>
|
<file>rc/window_undock_pressed@2x.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
<qresource prefix="qdarkstyle_midnight_blue">
|
<qresource prefix="qdarkstyle_midnight_blue">
|
||||||
<file>style.qss</file>
|
<file>style.qss</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|
|
@ -235,19 +235,19 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qgroupbox
|
||||||
|
|
||||||
--------------------------------------------------------------------------- */
|
--------------------------------------------------------------------------- */
|
||||||
QGroupBox {
|
QGroupBox {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
border: 1px solid #32414B;
|
border: 1px solid #32414B;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
margin-top: 12px;
|
margin-top: 12px;
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
QGroupBox::title {
|
QGroupBox::title {
|
||||||
subcontrol-origin: margin;
|
subcontrol-origin: margin;
|
||||||
subcontrol-position: top left;
|
subcontrol-position: top left;
|
||||||
padding-left: 3px;
|
padding-left: 3px;
|
||||||
padding-right: 5px;
|
padding-right: 5px;
|
||||||
padding-top: 4px;
|
padding-top: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
QGroupBox::indicator {
|
QGroupBox::indicator {
|
||||||
|
@ -2205,7 +2205,179 @@ QPushButton#buttonRefreshDevices {
|
||||||
padding: 0px 0px;
|
padding: 0px 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QSpinBox#spinboxLStickRange,
|
||||||
|
QSpinBox#spinboxRStickRange {
|
||||||
|
min-width: 38px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QGroupBox#motionGroup::indicator,
|
||||||
|
QGroupBox#vibrationGroup::indicator {
|
||||||
|
margin-left: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget#bottomPerGameInput QGroupBox#motionGroup,
|
||||||
|
QWidget#bottomPerGameInput QGroupBox#vibrationGroup,
|
||||||
|
QWidget#bottomPerGameInput QGroupBox#inputConfigGroup {
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QGroupBox#motionGroup::title,
|
||||||
|
QGroupBox#vibrationGroup::title {
|
||||||
|
spacing: 2px;
|
||||||
|
padding-left: 1px;
|
||||||
|
padding-right: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QListWidget#selectorList {
|
||||||
|
background-color: #0f1922;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSpinBox,
|
||||||
|
QLineEdit,
|
||||||
|
QTreeView#hotkey_list,
|
||||||
|
QScrollArea#scrollArea QTreeView {
|
||||||
|
background-color: #0f1922;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget#bottomPerGameInput,
|
||||||
|
QWidget#topControllerApplet,
|
||||||
|
QWidget#bottomControllerApplet,
|
||||||
|
QGroupBox#groupPlayer1Connected:checked,
|
||||||
|
QGroupBox#groupPlayer2Connected:checked,
|
||||||
|
QGroupBox#groupPlayer3Connected:checked,
|
||||||
|
QGroupBox#groupPlayer4Connected:checked,
|
||||||
|
QGroupBox#groupPlayer5Connected:checked,
|
||||||
|
QGroupBox#groupPlayer6Connected:checked,
|
||||||
|
QGroupBox#groupPlayer7Connected:checked,
|
||||||
|
QGroupBox#groupPlayer8Connected:checked {
|
||||||
|
background-color: #0f1922;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget#topPerGameInput,
|
||||||
|
QWidget#middleControllerApplet {
|
||||||
|
background-color: #19232d;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget#topPerGameInput QComboBox,
|
||||||
|
QWidget#middleControllerApplet QComboBox {
|
||||||
|
padding-right: 2px;
|
||||||
|
width: 127px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QGroupBox#handheldGroup {
|
||||||
|
padding-left: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRadioButton#radioDocked {
|
||||||
|
margin-left: -1px;
|
||||||
|
padding-left: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRadioButton#radioDocked::indicator {
|
||||||
|
margin-left: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QRadioButton#radioUndocked {
|
||||||
|
margin-right: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget#connectedControllers {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget#playersSupported,
|
||||||
|
QWidget#controllersSupported,
|
||||||
|
QWidget#controllerSupported1,
|
||||||
|
QWidget#controllerSupported2,
|
||||||
|
QWidget#controllerSupported3,
|
||||||
|
QWidget#controllerSupported4,
|
||||||
|
QWidget#controllerSupported5,
|
||||||
|
QWidget#controllerSupported6 {
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
QGroupBox#groupPlayer1Connected,
|
||||||
|
QGroupBox#groupPlayer2Connected,
|
||||||
|
QGroupBox#groupPlayer3Connected,
|
||||||
|
QGroupBox#groupPlayer4Connected,
|
||||||
|
QGroupBox#groupPlayer5Connected,
|
||||||
|
QGroupBox#groupPlayer6Connected,
|
||||||
|
QGroupBox#groupPlayer7Connected,
|
||||||
|
QGroupBox#groupPlayer8Connected {
|
||||||
|
border: 1px solid #76797c;
|
||||||
|
border-radius: 3px;
|
||||||
|
padding: 0px;
|
||||||
|
min-height: 98px;
|
||||||
|
max-height: 98px;
|
||||||
|
margin-top: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QGroupBox#groupPlayer1Connected:unchecked,
|
||||||
|
QGroupBox#groupPlayer2Connected:unchecked,
|
||||||
|
QGroupBox#groupPlayer3Connected:unchecked,
|
||||||
|
QGroupBox#groupPlayer4Connected:unchecked,
|
||||||
|
QGroupBox#groupPlayer5Connected:unchecked,
|
||||||
|
QGroupBox#groupPlayer6Connected:unchecked,
|
||||||
|
QGroupBox#groupPlayer7Connected:unchecked,
|
||||||
|
QGroupBox#groupPlayer8Connected:unchecked {
|
||||||
|
border: 1px solid #32414b;
|
||||||
|
}
|
||||||
|
|
||||||
|
QGroupBox#groupPlayer1Connected::title,
|
||||||
|
QGroupBox#groupPlayer2Connected::title,
|
||||||
|
QGroupBox#groupPlayer3Connected::title,
|
||||||
|
QGroupBox#groupPlayer4Connected::title,
|
||||||
|
QGroupBox#groupPlayer5Connected::title,
|
||||||
|
QGroupBox#groupPlayer6Connected::title,
|
||||||
|
QGroupBox#groupPlayer7Connected::title,
|
||||||
|
QGroupBox#groupPlayer8Connected::title {
|
||||||
|
subcontrol-origin: margin;
|
||||||
|
subcontrol-position: top left;
|
||||||
|
padding-left: 0px;
|
||||||
|
padding-right: 0px;
|
||||||
|
padding-top: 1px;
|
||||||
|
margin-left: -2px;
|
||||||
|
margin-right: -4px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QCheckBox#checkboxPlayer1Connected,
|
||||||
|
QCheckBox#checkboxPlayer2Connected,
|
||||||
|
QCheckBox#checkboxPlayer3Connected,
|
||||||
|
QCheckBox#checkboxPlayer4Connected,
|
||||||
|
QCheckBox#checkboxPlayer5Connected,
|
||||||
|
QCheckBox#checkboxPlayer6Connected,
|
||||||
|
QCheckBox#checkboxPlayer7Connected,
|
||||||
|
QCheckBox#checkboxPlayer8Connected {
|
||||||
|
spacing: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget#connectedControllers QLabel {
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget#Player1LEDs,
|
||||||
|
QWidget#Player2LEDs,
|
||||||
|
QWidget#Player3LEDs,
|
||||||
|
QWidget#Player4LEDs,
|
||||||
|
QWidget#Player5LEDs,
|
||||||
|
QWidget#Player6LEDs,
|
||||||
|
QWidget#Player7LEDs,
|
||||||
|
QWidget#Player8LEDs {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget#Player1LEDs QCheckBox,
|
||||||
|
QWidget#Player2LEDs QCheckBox,
|
||||||
|
QWidget#Player3LEDs QCheckBox,
|
||||||
|
QWidget#Player4LEDs QCheckBox,
|
||||||
|
QWidget#Player5LEDs QCheckBox,
|
||||||
|
QWidget#Player6LEDs QCheckBox,
|
||||||
|
QWidget#Player7LEDs QCheckBox,
|
||||||
|
QWidget#Player8LEDs QCheckBox,
|
||||||
QCheckBox#checkboxPlayer1Connected,
|
QCheckBox#checkboxPlayer1Connected,
|
||||||
QCheckBox#checkboxPlayer2Connected,
|
QCheckBox#checkboxPlayer2Connected,
|
||||||
QCheckBox#checkboxPlayer3Connected,
|
QCheckBox#checkboxPlayer3Connected,
|
||||||
|
@ -2215,6 +2387,34 @@ QCheckBox#checkboxPlayer6Connected,
|
||||||
QCheckBox#checkboxPlayer7Connected,
|
QCheckBox#checkboxPlayer7Connected,
|
||||||
QCheckBox#checkboxPlayer8Connected {
|
QCheckBox#checkboxPlayer8Connected {
|
||||||
spacing: 0px;
|
spacing: 0px;
|
||||||
|
padding-top: 0px;
|
||||||
|
padding-bottom: 0px;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget#Player1LEDs QCheckBox::indicator,
|
||||||
|
QWidget#Player2LEDs QCheckBox::indicator,
|
||||||
|
QWidget#Player3LEDs QCheckBox::indicator,
|
||||||
|
QWidget#Player4LEDs QCheckBox::indicator,
|
||||||
|
QWidget#Player5LEDs QCheckBox::indicator,
|
||||||
|
QWidget#Player6LEDs QCheckBox::indicator,
|
||||||
|
QWidget#Player7LEDs QCheckBox::indicator,
|
||||||
|
QWidget#Player8LEDs QCheckBox::indicator {
|
||||||
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
|
margin-left: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer1Connected::indicator,
|
||||||
|
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer2Connected::indicator,
|
||||||
|
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer3Connected::indicator,
|
||||||
|
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer4Connected::indicator,
|
||||||
|
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer5Connected::indicator,
|
||||||
|
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer6Connected::indicator,
|
||||||
|
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer7Connected::indicator,
|
||||||
|
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer8Connected::indicator {
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
QCheckBox#checkboxPlayer1Connected::indicator,
|
QCheckBox#checkboxPlayer1Connected::indicator,
|
||||||
|
@ -2227,8 +2427,25 @@ QCheckBox#checkboxPlayer7Connected::indicator,
|
||||||
QCheckBox#checkboxPlayer8Connected::indicator {
|
QCheckBox#checkboxPlayer8Connected::indicator {
|
||||||
width: 14px;
|
width: 14px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
|
margin-left: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QWidget#Player1LEDs QCheckBox::indicator:checked,
|
||||||
|
QWidget#Player2LEDs QCheckBox::indicator:checked,
|
||||||
|
QWidget#Player3LEDs QCheckBox::indicator:checked,
|
||||||
|
QWidget#Player4LEDs QCheckBox::indicator:checked,
|
||||||
|
QWidget#Player5LEDs QCheckBox::indicator:checked,
|
||||||
|
QWidget#Player6LEDs QCheckBox::indicator:checked,
|
||||||
|
QWidget#Player7LEDs QCheckBox::indicator:checked,
|
||||||
|
QWidget#Player8LEDs QCheckBox::indicator:checked,
|
||||||
|
QGroupBox#groupPlayer1Connected::indicator:checked,
|
||||||
|
QGroupBox#groupPlayer2Connected::indicator:checked,
|
||||||
|
QGroupBox#groupPlayer3Connected::indicator:checked,
|
||||||
|
QGroupBox#groupPlayer4Connected::indicator:checked,
|
||||||
|
QGroupBox#groupPlayer5Connected::indicator:checked,
|
||||||
|
QGroupBox#groupPlayer6Connected::indicator:checked,
|
||||||
|
QGroupBox#groupPlayer7Connected::indicator:checked,
|
||||||
|
QGroupBox#groupPlayer8Connected::indicator:checked,
|
||||||
QCheckBox#checkboxPlayer1Connected::indicator:checked,
|
QCheckBox#checkboxPlayer1Connected::indicator:checked,
|
||||||
QCheckBox#checkboxPlayer2Connected::indicator:checked,
|
QCheckBox#checkboxPlayer2Connected::indicator:checked,
|
||||||
QCheckBox#checkboxPlayer3Connected::indicator:checked,
|
QCheckBox#checkboxPlayer3Connected::indicator:checked,
|
||||||
|
@ -2244,6 +2461,22 @@ QGroupBox#groupConnectedController::indicator:checked {
|
||||||
image: none;
|
image: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QWidget#Player1LEDs QCheckBox::indicator:unchecked,
|
||||||
|
QWidget#Player2LEDs QCheckBox::indicator:unchecked,
|
||||||
|
QWidget#Player3LEDs QCheckBox::indicator:unchecked,
|
||||||
|
QWidget#Player4LEDs QCheckBox::indicator:unchecked,
|
||||||
|
QWidget#Player5LEDs QCheckBox::indicator:unchecked,
|
||||||
|
QWidget#Player6LEDs QCheckBox::indicator:unchecked,
|
||||||
|
QWidget#Player7LEDs QCheckBox::indicator:unchecked,
|
||||||
|
QWidget#Player8LEDs QCheckBox::indicator:unchecked,
|
||||||
|
QGroupBox#groupPlayer1Connected::indicator:unchecked,
|
||||||
|
QGroupBox#groupPlayer2Connected::indicator:unchecked,
|
||||||
|
QGroupBox#groupPlayer3Connected::indicator:unchecked,
|
||||||
|
QGroupBox#groupPlayer4Connected::indicator:unchecked,
|
||||||
|
QGroupBox#groupPlayer5Connected::indicator:unchecked,
|
||||||
|
QGroupBox#groupPlayer6Connected::indicator:unchecked,
|
||||||
|
QGroupBox#groupPlayer7Connected::indicator:unchecked,
|
||||||
|
QGroupBox#groupPlayer8Connected::indicator:unchecked,
|
||||||
QCheckBox#checkboxPlayer1Connected::indicator:unchecked,
|
QCheckBox#checkboxPlayer1Connected::indicator:unchecked,
|
||||||
QCheckBox#checkboxPlayer2Connected::indicator:unchecked,
|
QCheckBox#checkboxPlayer2Connected::indicator:unchecked,
|
||||||
QCheckBox#checkboxPlayer3Connected::indicator:unchecked,
|
QCheckBox#checkboxPlayer3Connected::indicator:unchecked,
|
||||||
|
@ -2255,34 +2488,17 @@ QCheckBox#checkboxPlayer8Connected::indicator:unchecked,
|
||||||
QGroupBox#groupConnectedController::indicator:unchecked {
|
QGroupBox#groupConnectedController::indicator:unchecked {
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
border: 1px solid #929192;
|
border: 1px solid #929192;
|
||||||
background: transparent;
|
background: #19232d;
|
||||||
image: none;
|
image: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
QSpinBox#spinboxLStickRange,
|
QWidget#controllerPlayer1,
|
||||||
QSpinBox#spinboxRStickRange {
|
QWidget#controllerPlayer2,
|
||||||
min-width: 38px;
|
QWidget#controllerPlayer3,
|
||||||
|
QWidget#controllerPlayer4,
|
||||||
|
QWidget#controllerPlayer5,
|
||||||
|
QWidget#controllerPlayer6,
|
||||||
|
QWidget#controllerPlayer7,
|
||||||
|
QWidget#controllerPlayer8 {
|
||||||
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
QGroupBox#motionGroup::indicator,
|
|
||||||
QGroupBox#vibrationGroup::indicator {
|
|
||||||
margin-left: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
QGroupBox#motionGroup::title,
|
|
||||||
QGroupBox#vibrationGroup::title {
|
|
||||||
spacing: 2px;
|
|
||||||
padding-left: 1px;
|
|
||||||
padding-right: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
QListWidget#selectorList {
|
|
||||||
background-color: #0f1922;
|
|
||||||
}
|
|
||||||
|
|
||||||
QSpinBox,
|
|
||||||
QLineEdit,
|
|
||||||
QTreeView#hotkey_list,
|
|
||||||
QScrollArea#scrollArea QTreeView {
|
|
||||||
background-color: #0f1922;
|
|
||||||
}
|
|
|
@ -126,6 +126,8 @@ add_library(core STATIC
|
||||||
file_sys/vfs_vector.h
|
file_sys/vfs_vector.h
|
||||||
file_sys/xts_archive.cpp
|
file_sys/xts_archive.cpp
|
||||||
file_sys/xts_archive.h
|
file_sys/xts_archive.h
|
||||||
|
frontend/applets/controller.cpp
|
||||||
|
frontend/applets/controller.h
|
||||||
frontend/applets/error.cpp
|
frontend/applets/error.cpp
|
||||||
frontend/applets/error.h
|
frontend/applets/error.h
|
||||||
frontend/applets/general_frontend.cpp
|
frontend/applets/general_frontend.cpp
|
||||||
|
@ -244,6 +246,8 @@ add_library(core STATIC
|
||||||
hle/service/am/applet_oe.h
|
hle/service/am/applet_oe.h
|
||||||
hle/service/am/applets/applets.cpp
|
hle/service/am/applets/applets.cpp
|
||||||
hle/service/am/applets/applets.h
|
hle/service/am/applets/applets.h
|
||||||
|
hle/service/am/applets/controller.cpp
|
||||||
|
hle/service/am/applets/controller.h
|
||||||
hle/service/am/applets/error.cpp
|
hle/service/am/applets/error.cpp
|
||||||
hle/service/am/applets/error.h
|
hle/service/am/applets/error.h
|
||||||
hle/service/am/applets/general_backend.cpp
|
hle/service/am/applets/general_backend.cpp
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
// Copyright 2020 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "common/assert.h"
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "core/core.h"
|
||||||
|
#include "core/frontend/applets/controller.h"
|
||||||
|
#include "core/hle/service/hid/controllers/npad.h"
|
||||||
|
#include "core/hle/service/hid/hid.h"
|
||||||
|
#include "core/hle/service/sm/sm.h"
|
||||||
|
|
||||||
|
namespace Core::Frontend {
|
||||||
|
|
||||||
|
ControllerApplet::~ControllerApplet() = default;
|
||||||
|
|
||||||
|
DefaultControllerApplet::~DefaultControllerApplet() = default;
|
||||||
|
|
||||||
|
void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callback,
|
||||||
|
ControllerParameters parameters) const {
|
||||||
|
LOG_INFO(Service_HID, "called, deducing the best configuration based on the given parameters!");
|
||||||
|
|
||||||
|
auto& npad =
|
||||||
|
Core::System::GetInstance()
|
||||||
|
.ServiceManager()
|
||||||
|
.GetService<Service::HID::Hid>("hid")
|
||||||
|
->GetAppletResource()
|
||||||
|
->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad);
|
||||||
|
|
||||||
|
auto& players = Settings::values.players;
|
||||||
|
|
||||||
|
const std::size_t min_supported_players =
|
||||||
|
parameters.enable_single_mode ? 1 : parameters.min_players;
|
||||||
|
|
||||||
|
// Disconnect Handheld first.
|
||||||
|
npad.DisconnectNPadAtIndex(8);
|
||||||
|
|
||||||
|
// Deduce the best configuration based on the input parameters.
|
||||||
|
for (std::size_t index = 0; index < players.size() - 2; ++index) {
|
||||||
|
// First, disconnect all controllers regardless of the value of keep_controllers_connected.
|
||||||
|
// This makes it easy to connect the desired controllers.
|
||||||
|
npad.DisconnectNPadAtIndex(index);
|
||||||
|
|
||||||
|
// Only connect the minimum number of required players.
|
||||||
|
if (index >= min_supported_players) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect controllers based on the following priority list from highest to lowest priority:
|
||||||
|
// Pro Controller -> Dual Joycons -> Left Joycon/Right Joycon -> Handheld
|
||||||
|
if (parameters.allow_pro_controller) {
|
||||||
|
npad.AddNewControllerAt(
|
||||||
|
npad.MapSettingsTypeToNPad(Settings::ControllerType::ProController), index);
|
||||||
|
} else if (parameters.allow_dual_joycons) {
|
||||||
|
npad.AddNewControllerAt(
|
||||||
|
npad.MapSettingsTypeToNPad(Settings::ControllerType::DualJoyconDetached), index);
|
||||||
|
} else if (parameters.allow_left_joycon && parameters.allow_right_joycon) {
|
||||||
|
// Assign left joycons to even player indices and right joycons to odd player indices.
|
||||||
|
// We do this since Captain Toad Treasure Tracker expects a left joycon for Player 1 and
|
||||||
|
// a right Joycon for Player 2 in 2 Player Assist mode.
|
||||||
|
if (index % 2 == 0) {
|
||||||
|
npad.AddNewControllerAt(
|
||||||
|
npad.MapSettingsTypeToNPad(Settings::ControllerType::LeftJoycon), index);
|
||||||
|
} else {
|
||||||
|
npad.AddNewControllerAt(
|
||||||
|
npad.MapSettingsTypeToNPad(Settings::ControllerType::RightJoycon), index);
|
||||||
|
}
|
||||||
|
} else if (index == 0 && parameters.enable_single_mode && parameters.allow_handheld &&
|
||||||
|
!Settings::values.use_docked_mode) {
|
||||||
|
// We should *never* reach here under any normal circumstances.
|
||||||
|
npad.AddNewControllerAt(npad.MapSettingsTypeToNPad(Settings::ControllerType::Handheld),
|
||||||
|
index);
|
||||||
|
} else {
|
||||||
|
UNREACHABLE_MSG("Unable to add a new controller based on the given parameters!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Core::Frontend
|
|
@ -0,0 +1,48 @@
|
||||||
|
// Copyright 2020 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#include "common/common_types.h"
|
||||||
|
|
||||||
|
namespace Core::Frontend {
|
||||||
|
|
||||||
|
using BorderColor = std::array<u8, 4>;
|
||||||
|
using ExplainText = std::array<char, 0x81>;
|
||||||
|
|
||||||
|
struct ControllerParameters {
|
||||||
|
s8 min_players{};
|
||||||
|
s8 max_players{};
|
||||||
|
bool keep_controllers_connected{};
|
||||||
|
bool enable_single_mode{};
|
||||||
|
bool enable_border_color{};
|
||||||
|
std::vector<BorderColor> border_colors{};
|
||||||
|
bool enable_explain_text{};
|
||||||
|
std::vector<ExplainText> explain_text{};
|
||||||
|
bool allow_pro_controller{};
|
||||||
|
bool allow_handheld{};
|
||||||
|
bool allow_dual_joycons{};
|
||||||
|
bool allow_left_joycon{};
|
||||||
|
bool allow_right_joycon{};
|
||||||
|
};
|
||||||
|
|
||||||
|
class ControllerApplet {
|
||||||
|
public:
|
||||||
|
virtual ~ControllerApplet();
|
||||||
|
|
||||||
|
virtual void ReconfigureControllers(std::function<void()> callback,
|
||||||
|
ControllerParameters parameters) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DefaultControllerApplet final : public ControllerApplet {
|
||||||
|
public:
|
||||||
|
~DefaultControllerApplet() override;
|
||||||
|
|
||||||
|
void ReconfigureControllers(std::function<void()> callback,
|
||||||
|
ControllerParameters parameters) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Core::Frontend
|
|
@ -5,6 +5,7 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
|
#include "core/frontend/applets/controller.h"
|
||||||
#include "core/frontend/applets/error.h"
|
#include "core/frontend/applets/error.h"
|
||||||
#include "core/frontend/applets/general_frontend.h"
|
#include "core/frontend/applets/general_frontend.h"
|
||||||
#include "core/frontend/applets/profile_select.h"
|
#include "core/frontend/applets/profile_select.h"
|
||||||
|
@ -15,6 +16,7 @@
|
||||||
#include "core/hle/kernel/writable_event.h"
|
#include "core/hle/kernel/writable_event.h"
|
||||||
#include "core/hle/service/am/am.h"
|
#include "core/hle/service/am/am.h"
|
||||||
#include "core/hle/service/am/applets/applets.h"
|
#include "core/hle/service/am/applets/applets.h"
|
||||||
|
#include "core/hle/service/am/applets/controller.h"
|
||||||
#include "core/hle/service/am/applets/error.h"
|
#include "core/hle/service/am/applets/error.h"
|
||||||
#include "core/hle/service/am/applets/general_backend.h"
|
#include "core/hle/service/am/applets/general_backend.h"
|
||||||
#include "core/hle/service/am/applets/profile_select.h"
|
#include "core/hle/service/am/applets/profile_select.h"
|
||||||
|
@ -140,14 +142,14 @@ void Applet::Initialize() {
|
||||||
|
|
||||||
AppletFrontendSet::AppletFrontendSet() = default;
|
AppletFrontendSet::AppletFrontendSet() = default;
|
||||||
|
|
||||||
AppletFrontendSet::AppletFrontendSet(ParentalControlsApplet parental_controls, ErrorApplet error,
|
AppletFrontendSet::AppletFrontendSet(ControllerApplet controller, ECommerceApplet e_commerce,
|
||||||
|
ErrorApplet error, ParentalControlsApplet parental_controls,
|
||||||
PhotoViewer photo_viewer, ProfileSelect profile_select,
|
PhotoViewer photo_viewer, ProfileSelect profile_select,
|
||||||
SoftwareKeyboard software_keyboard, WebBrowser web_browser,
|
SoftwareKeyboard software_keyboard, WebBrowser web_browser)
|
||||||
ECommerceApplet e_commerce)
|
: controller{std::move(controller)}, e_commerce{std::move(e_commerce)}, error{std::move(error)},
|
||||||
: parental_controls{std::move(parental_controls)}, error{std::move(error)},
|
parental_controls{std::move(parental_controls)}, photo_viewer{std::move(photo_viewer)},
|
||||||
photo_viewer{std::move(photo_viewer)}, profile_select{std::move(profile_select)},
|
profile_select{std::move(profile_select)}, software_keyboard{std::move(software_keyboard)},
|
||||||
software_keyboard{std::move(software_keyboard)}, web_browser{std::move(web_browser)},
|
web_browser{std::move(web_browser)} {}
|
||||||
e_commerce{std::move(e_commerce)} {}
|
|
||||||
|
|
||||||
AppletFrontendSet::~AppletFrontendSet() = default;
|
AppletFrontendSet::~AppletFrontendSet() = default;
|
||||||
|
|
||||||
|
@ -164,20 +166,37 @@ const AppletFrontendSet& AppletManager::GetAppletFrontendSet() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) {
|
void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) {
|
||||||
if (set.parental_controls != nullptr)
|
if (set.controller != nullptr) {
|
||||||
frontend.parental_controls = std::move(set.parental_controls);
|
frontend.controller = std::move(set.controller);
|
||||||
if (set.error != nullptr)
|
}
|
||||||
frontend.error = std::move(set.error);
|
|
||||||
if (set.photo_viewer != nullptr)
|
if (set.e_commerce != nullptr) {
|
||||||
frontend.photo_viewer = std::move(set.photo_viewer);
|
|
||||||
if (set.profile_select != nullptr)
|
|
||||||
frontend.profile_select = std::move(set.profile_select);
|
|
||||||
if (set.software_keyboard != nullptr)
|
|
||||||
frontend.software_keyboard = std::move(set.software_keyboard);
|
|
||||||
if (set.web_browser != nullptr)
|
|
||||||
frontend.web_browser = std::move(set.web_browser);
|
|
||||||
if (set.e_commerce != nullptr)
|
|
||||||
frontend.e_commerce = std::move(set.e_commerce);
|
frontend.e_commerce = std::move(set.e_commerce);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (set.error != nullptr) {
|
||||||
|
frontend.error = std::move(set.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (set.parental_controls != nullptr) {
|
||||||
|
frontend.parental_controls = std::move(set.parental_controls);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (set.photo_viewer != nullptr) {
|
||||||
|
frontend.photo_viewer = std::move(set.photo_viewer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (set.profile_select != nullptr) {
|
||||||
|
frontend.profile_select = std::move(set.profile_select);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (set.software_keyboard != nullptr) {
|
||||||
|
frontend.software_keyboard = std::move(set.software_keyboard);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (set.web_browser != nullptr) {
|
||||||
|
frontend.web_browser = std::move(set.web_browser);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppletManager::SetDefaultAppletFrontendSet() {
|
void AppletManager::SetDefaultAppletFrontendSet() {
|
||||||
|
@ -186,15 +205,23 @@ void AppletManager::SetDefaultAppletFrontendSet() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppletManager::SetDefaultAppletsIfMissing() {
|
void AppletManager::SetDefaultAppletsIfMissing() {
|
||||||
if (frontend.parental_controls == nullptr) {
|
if (frontend.controller == nullptr) {
|
||||||
frontend.parental_controls =
|
frontend.controller = std::make_unique<Core::Frontend::DefaultControllerApplet>();
|
||||||
std::make_unique<Core::Frontend::DefaultParentalControlsApplet>();
|
}
|
||||||
|
|
||||||
|
if (frontend.e_commerce == nullptr) {
|
||||||
|
frontend.e_commerce = std::make_unique<Core::Frontend::DefaultECommerceApplet>();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frontend.error == nullptr) {
|
if (frontend.error == nullptr) {
|
||||||
frontend.error = std::make_unique<Core::Frontend::DefaultErrorApplet>();
|
frontend.error = std::make_unique<Core::Frontend::DefaultErrorApplet>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (frontend.parental_controls == nullptr) {
|
||||||
|
frontend.parental_controls =
|
||||||
|
std::make_unique<Core::Frontend::DefaultParentalControlsApplet>();
|
||||||
|
}
|
||||||
|
|
||||||
if (frontend.photo_viewer == nullptr) {
|
if (frontend.photo_viewer == nullptr) {
|
||||||
frontend.photo_viewer = std::make_unique<Core::Frontend::DefaultPhotoViewerApplet>();
|
frontend.photo_viewer = std::make_unique<Core::Frontend::DefaultPhotoViewerApplet>();
|
||||||
}
|
}
|
||||||
|
@ -211,10 +238,6 @@ void AppletManager::SetDefaultAppletsIfMissing() {
|
||||||
if (frontend.web_browser == nullptr) {
|
if (frontend.web_browser == nullptr) {
|
||||||
frontend.web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>();
|
frontend.web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frontend.e_commerce == nullptr) {
|
|
||||||
frontend.e_commerce = std::make_unique<Core::Frontend::DefaultECommerceApplet>();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppletManager::ClearAll() {
|
void AppletManager::ClearAll() {
|
||||||
|
@ -225,6 +248,8 @@ std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id) const {
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case AppletId::Auth:
|
case AppletId::Auth:
|
||||||
return std::make_shared<Auth>(system, *frontend.parental_controls);
|
return std::make_shared<Auth>(system, *frontend.parental_controls);
|
||||||
|
case AppletId::Controller:
|
||||||
|
return std::make_shared<Controller>(system, *frontend.controller);
|
||||||
case AppletId::Error:
|
case AppletId::Error:
|
||||||
return std::make_shared<Error>(system, *frontend.error);
|
return std::make_shared<Error>(system, *frontend.error);
|
||||||
case AppletId::ProfileSelect:
|
case AppletId::ProfileSelect:
|
||||||
|
|
|
@ -17,6 +17,7 @@ class System;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Core::Frontend {
|
namespace Core::Frontend {
|
||||||
|
class ControllerApplet;
|
||||||
class ECommerceApplet;
|
class ECommerceApplet;
|
||||||
class ErrorApplet;
|
class ErrorApplet;
|
||||||
class ParentalControlsApplet;
|
class ParentalControlsApplet;
|
||||||
|
@ -155,19 +156,20 @@ protected:
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AppletFrontendSet {
|
struct AppletFrontendSet {
|
||||||
using ParentalControlsApplet = std::unique_ptr<Core::Frontend::ParentalControlsApplet>;
|
using ControllerApplet = std::unique_ptr<Core::Frontend::ControllerApplet>;
|
||||||
|
using ECommerceApplet = std::unique_ptr<Core::Frontend::ECommerceApplet>;
|
||||||
using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>;
|
using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>;
|
||||||
|
using ParentalControlsApplet = std::unique_ptr<Core::Frontend::ParentalControlsApplet>;
|
||||||
using PhotoViewer = std::unique_ptr<Core::Frontend::PhotoViewerApplet>;
|
using PhotoViewer = std::unique_ptr<Core::Frontend::PhotoViewerApplet>;
|
||||||
using ProfileSelect = std::unique_ptr<Core::Frontend::ProfileSelectApplet>;
|
using ProfileSelect = std::unique_ptr<Core::Frontend::ProfileSelectApplet>;
|
||||||
using SoftwareKeyboard = std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet>;
|
using SoftwareKeyboard = std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet>;
|
||||||
using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>;
|
using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>;
|
||||||
using ECommerceApplet = std::unique_ptr<Core::Frontend::ECommerceApplet>;
|
|
||||||
|
|
||||||
AppletFrontendSet();
|
AppletFrontendSet();
|
||||||
AppletFrontendSet(ParentalControlsApplet parental_controls, ErrorApplet error,
|
AppletFrontendSet(ControllerApplet controller, ECommerceApplet e_commerce, ErrorApplet error,
|
||||||
PhotoViewer photo_viewer, ProfileSelect profile_select,
|
ParentalControlsApplet parental_controls, PhotoViewer photo_viewer,
|
||||||
SoftwareKeyboard software_keyboard, WebBrowser web_browser,
|
ProfileSelect profile_select, SoftwareKeyboard software_keyboard,
|
||||||
ECommerceApplet e_commerce);
|
WebBrowser web_browser);
|
||||||
~AppletFrontendSet();
|
~AppletFrontendSet();
|
||||||
|
|
||||||
AppletFrontendSet(const AppletFrontendSet&) = delete;
|
AppletFrontendSet(const AppletFrontendSet&) = delete;
|
||||||
|
@ -176,13 +178,14 @@ struct AppletFrontendSet {
|
||||||
AppletFrontendSet(AppletFrontendSet&&) noexcept;
|
AppletFrontendSet(AppletFrontendSet&&) noexcept;
|
||||||
AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept;
|
AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept;
|
||||||
|
|
||||||
ParentalControlsApplet parental_controls;
|
ControllerApplet controller;
|
||||||
|
ECommerceApplet e_commerce;
|
||||||
ErrorApplet error;
|
ErrorApplet error;
|
||||||
|
ParentalControlsApplet parental_controls;
|
||||||
PhotoViewer photo_viewer;
|
PhotoViewer photo_viewer;
|
||||||
ProfileSelect profile_select;
|
ProfileSelect profile_select;
|
||||||
SoftwareKeyboard software_keyboard;
|
SoftwareKeyboard software_keyboard;
|
||||||
WebBrowser web_browser;
|
WebBrowser web_browser;
|
||||||
ECommerceApplet e_commerce;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class AppletManager {
|
class AppletManager {
|
||||||
|
|
|
@ -0,0 +1,210 @@
|
||||||
|
// Copyright 2020 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "common/assert.h"
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "common/string_util.h"
|
||||||
|
#include "core/core.h"
|
||||||
|
#include "core/frontend/applets/controller.h"
|
||||||
|
#include "core/hle/result.h"
|
||||||
|
#include "core/hle/service/am/am.h"
|
||||||
|
#include "core/hle/service/am/applets/controller.h"
|
||||||
|
#include "core/hle/service/hid/controllers/npad.h"
|
||||||
|
|
||||||
|
namespace Service::AM::Applets {
|
||||||
|
|
||||||
|
// This error code (0x183ACA) is thrown when the applet fails to initialize.
|
||||||
|
[[maybe_unused]] constexpr ResultCode ERR_CONTROLLER_APPLET_3101{ErrorModule::HID, 3101};
|
||||||
|
// This error code (0x183CCA) is thrown when the u32 result in ControllerSupportResultInfo is 2.
|
||||||
|
[[maybe_unused]] constexpr ResultCode ERR_CONTROLLER_APPLET_3102{ErrorModule::HID, 3102};
|
||||||
|
|
||||||
|
static Core::Frontend::ControllerParameters ConvertToFrontendParameters(
|
||||||
|
ControllerSupportArgPrivate private_arg, ControllerSupportArgHeader header, bool enable_text,
|
||||||
|
std::vector<IdentificationColor> identification_colors, std::vector<ExplainText> text) {
|
||||||
|
HID::Controller_NPad::NPadType npad_style_set;
|
||||||
|
npad_style_set.raw = private_arg.style_set;
|
||||||
|
|
||||||
|
return {
|
||||||
|
.min_players = std::max(s8(1), header.player_count_min),
|
||||||
|
.max_players = header.player_count_max,
|
||||||
|
.keep_controllers_connected = header.enable_take_over_connection,
|
||||||
|
.enable_single_mode = header.enable_single_mode,
|
||||||
|
.enable_border_color = header.enable_identification_color,
|
||||||
|
.border_colors = identification_colors,
|
||||||
|
.enable_explain_text = enable_text,
|
||||||
|
.explain_text = text,
|
||||||
|
.allow_pro_controller = npad_style_set.pro_controller == 1,
|
||||||
|
.allow_handheld = npad_style_set.handheld == 1,
|
||||||
|
.allow_dual_joycons = npad_style_set.joycon_dual == 1,
|
||||||
|
.allow_left_joycon = npad_style_set.joycon_left == 1,
|
||||||
|
.allow_right_joycon = npad_style_set.joycon_right == 1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Controller::Controller(Core::System& system_, const Core::Frontend::ControllerApplet& frontend_)
|
||||||
|
: Applet{system_.Kernel()}, frontend(frontend_) {}
|
||||||
|
|
||||||
|
Controller::~Controller() = default;
|
||||||
|
|
||||||
|
void Controller::Initialize() {
|
||||||
|
Applet::Initialize();
|
||||||
|
|
||||||
|
LOG_INFO(Service_HID, "Initializing Controller Applet.");
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_HID,
|
||||||
|
"Initializing Applet with common_args: arg_version={}, lib_version={}, "
|
||||||
|
"play_startup_sound={}, size={}, system_tick={}, theme_color={}",
|
||||||
|
common_args.arguments_version, common_args.library_version,
|
||||||
|
common_args.play_startup_sound, common_args.size, common_args.system_tick,
|
||||||
|
common_args.theme_color);
|
||||||
|
|
||||||
|
library_applet_version = LibraryAppletVersion{common_args.library_version};
|
||||||
|
|
||||||
|
const auto private_arg_storage = broker.PopNormalDataToApplet();
|
||||||
|
ASSERT(private_arg_storage != nullptr);
|
||||||
|
|
||||||
|
const auto& private_arg = private_arg_storage->GetData();
|
||||||
|
ASSERT(private_arg.size() == sizeof(ControllerSupportArgPrivate));
|
||||||
|
|
||||||
|
std::memcpy(&controller_private_arg, private_arg.data(), sizeof(ControllerSupportArgPrivate));
|
||||||
|
ASSERT_MSG(controller_private_arg.arg_private_size == sizeof(ControllerSupportArgPrivate),
|
||||||
|
"Unknown ControllerSupportArgPrivate revision={} with size={}",
|
||||||
|
library_applet_version, controller_private_arg.arg_private_size);
|
||||||
|
|
||||||
|
switch (controller_private_arg.mode) {
|
||||||
|
case ControllerSupportMode::ShowControllerSupport: {
|
||||||
|
const auto user_arg_storage = broker.PopNormalDataToApplet();
|
||||||
|
ASSERT(user_arg_storage != nullptr);
|
||||||
|
|
||||||
|
const auto& user_arg = user_arg_storage->GetData();
|
||||||
|
switch (library_applet_version) {
|
||||||
|
case LibraryAppletVersion::Version3:
|
||||||
|
case LibraryAppletVersion::Version4:
|
||||||
|
case LibraryAppletVersion::Version5:
|
||||||
|
ASSERT(user_arg.size() == sizeof(ControllerSupportArgOld));
|
||||||
|
std::memcpy(&controller_user_arg_old, user_arg.data(), sizeof(ControllerSupportArgOld));
|
||||||
|
break;
|
||||||
|
case LibraryAppletVersion::Version7:
|
||||||
|
ASSERT(user_arg.size() == sizeof(ControllerSupportArgNew));
|
||||||
|
std::memcpy(&controller_user_arg_new, user_arg.data(), sizeof(ControllerSupportArgNew));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
UNIMPLEMENTED_MSG("Unknown ControllerSupportArg revision={} with size={}",
|
||||||
|
library_applet_version, controller_private_arg.arg_size);
|
||||||
|
ASSERT(user_arg.size() >= sizeof(ControllerSupportArgNew));
|
||||||
|
std::memcpy(&controller_user_arg_new, user_arg.data(), sizeof(ControllerSupportArgNew));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ControllerSupportMode::ShowControllerStrapGuide:
|
||||||
|
case ControllerSupportMode::ShowControllerFirmwareUpdate:
|
||||||
|
default: {
|
||||||
|
UNIMPLEMENTED_MSG("Unimplemented ControllerSupportMode={}", controller_private_arg.mode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Controller::TransactionComplete() const {
|
||||||
|
return complete;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultCode Controller::GetStatus() const {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Controller::ExecuteInteractive() {
|
||||||
|
UNREACHABLE_MSG("Attempted to call interactive execution on non-interactive applet.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Controller::Execute() {
|
||||||
|
switch (controller_private_arg.mode) {
|
||||||
|
case ControllerSupportMode::ShowControllerSupport: {
|
||||||
|
const auto parameters = [this] {
|
||||||
|
switch (library_applet_version) {
|
||||||
|
case LibraryAppletVersion::Version3:
|
||||||
|
case LibraryAppletVersion::Version4:
|
||||||
|
case LibraryAppletVersion::Version5:
|
||||||
|
return ConvertToFrontendParameters(
|
||||||
|
controller_private_arg, controller_user_arg_old.header,
|
||||||
|
controller_user_arg_old.enable_explain_text,
|
||||||
|
std::vector<IdentificationColor>(
|
||||||
|
controller_user_arg_old.identification_colors.begin(),
|
||||||
|
controller_user_arg_old.identification_colors.end()),
|
||||||
|
std::vector<ExplainText>(controller_user_arg_old.explain_text.begin(),
|
||||||
|
controller_user_arg_old.explain_text.end()));
|
||||||
|
case LibraryAppletVersion::Version7:
|
||||||
|
default:
|
||||||
|
return ConvertToFrontendParameters(
|
||||||
|
controller_private_arg, controller_user_arg_new.header,
|
||||||
|
controller_user_arg_new.enable_explain_text,
|
||||||
|
std::vector<IdentificationColor>(
|
||||||
|
controller_user_arg_new.identification_colors.begin(),
|
||||||
|
controller_user_arg_new.identification_colors.end()),
|
||||||
|
std::vector<ExplainText>(controller_user_arg_new.explain_text.begin(),
|
||||||
|
controller_user_arg_new.explain_text.end()));
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
|
is_single_mode = parameters.enable_single_mode;
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_HID,
|
||||||
|
"Controller Parameters: min_players={}, max_players={}, "
|
||||||
|
"keep_controllers_connected={}, enable_single_mode={}, enable_border_color={}, "
|
||||||
|
"enable_explain_text={}, allow_pro_controller={}, allow_handheld={}, "
|
||||||
|
"allow_dual_joycons={}, allow_left_joycon={}, allow_right_joycon={}",
|
||||||
|
parameters.min_players, parameters.max_players,
|
||||||
|
parameters.keep_controllers_connected, parameters.enable_single_mode,
|
||||||
|
parameters.enable_border_color, parameters.enable_explain_text,
|
||||||
|
parameters.allow_pro_controller, parameters.allow_handheld,
|
||||||
|
parameters.allow_dual_joycons, parameters.allow_left_joycon,
|
||||||
|
parameters.allow_right_joycon);
|
||||||
|
|
||||||
|
frontend.ReconfigureControllers([this] { ConfigurationComplete(); }, parameters);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ControllerSupportMode::ShowControllerStrapGuide:
|
||||||
|
case ControllerSupportMode::ShowControllerFirmwareUpdate:
|
||||||
|
default: {
|
||||||
|
ConfigurationComplete();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Controller::ConfigurationComplete() {
|
||||||
|
ControllerSupportResultInfo result_info{};
|
||||||
|
|
||||||
|
const auto& players = Settings::values.players;
|
||||||
|
|
||||||
|
// If enable_single_mode is enabled, player_count is 1 regardless of any other parameters.
|
||||||
|
// Otherwise, only count connected players from P1-P8.
|
||||||
|
result_info.player_count =
|
||||||
|
is_single_mode ? 1
|
||||||
|
: static_cast<s8>(std::count_if(
|
||||||
|
players.begin(), players.end() - 2,
|
||||||
|
[](Settings::PlayerInput player) { return player.connected; }));
|
||||||
|
|
||||||
|
result_info.selected_id = HID::Controller_NPad::IndexToNPad(
|
||||||
|
std::distance(players.begin(),
|
||||||
|
std::find_if(players.begin(), players.end(),
|
||||||
|
[](Settings::PlayerInput player) { return player.connected; })));
|
||||||
|
|
||||||
|
result_info.result = 0;
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_HID, "Result Info: player_count={}, selected_id={}, result={}",
|
||||||
|
result_info.player_count, result_info.selected_id, result_info.result);
|
||||||
|
|
||||||
|
complete = true;
|
||||||
|
out_data = std::vector<u8>(sizeof(ControllerSupportResultInfo));
|
||||||
|
std::memcpy(out_data.data(), &result_info, out_data.size());
|
||||||
|
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(out_data)));
|
||||||
|
broker.SignalStateChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Service::AM::Applets
|
|
@ -0,0 +1,123 @@
|
||||||
|
// Copyright 2020 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "common/common_funcs.h"
|
||||||
|
#include "common/common_types.h"
|
||||||
|
#include "core/hle/result.h"
|
||||||
|
#include "core/hle/service/am/applets/applets.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Service::AM::Applets {
|
||||||
|
|
||||||
|
using IdentificationColor = std::array<u8, 4>;
|
||||||
|
using ExplainText = std::array<char, 0x81>;
|
||||||
|
|
||||||
|
enum class LibraryAppletVersion : u32_le {
|
||||||
|
Version3 = 0x3, // 1.0.0 - 2.3.0
|
||||||
|
Version4 = 0x4, // 3.0.0 - 5.1.0
|
||||||
|
Version5 = 0x5, // 6.0.0 - 7.0.1
|
||||||
|
Version7 = 0x7, // 8.0.0+
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class ControllerSupportMode : u8 {
|
||||||
|
ShowControllerSupport = 0,
|
||||||
|
ShowControllerStrapGuide = 1,
|
||||||
|
ShowControllerFirmwareUpdate = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class ControllerSupportCaller : u8 {
|
||||||
|
Application = 0,
|
||||||
|
System = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ControllerSupportArgPrivate {
|
||||||
|
u32 arg_private_size{};
|
||||||
|
u32 arg_size{};
|
||||||
|
bool flag_0{};
|
||||||
|
bool flag_1{};
|
||||||
|
ControllerSupportMode mode{};
|
||||||
|
ControllerSupportCaller caller{};
|
||||||
|
u32 style_set{};
|
||||||
|
u32 joy_hold_type{};
|
||||||
|
};
|
||||||
|
static_assert(sizeof(ControllerSupportArgPrivate) == 0x14,
|
||||||
|
"ControllerSupportArgPrivate has incorrect size.");
|
||||||
|
|
||||||
|
struct ControllerSupportArgHeader {
|
||||||
|
s8 player_count_min{};
|
||||||
|
s8 player_count_max{};
|
||||||
|
bool enable_take_over_connection{};
|
||||||
|
bool enable_left_justify{};
|
||||||
|
bool enable_permit_joy_dual{};
|
||||||
|
bool enable_single_mode{};
|
||||||
|
bool enable_identification_color{};
|
||||||
|
};
|
||||||
|
static_assert(sizeof(ControllerSupportArgHeader) == 0x7,
|
||||||
|
"ControllerSupportArgHeader has incorrect size.");
|
||||||
|
|
||||||
|
// LibraryAppletVersion 0x3, 0x4, 0x5
|
||||||
|
struct ControllerSupportArgOld {
|
||||||
|
ControllerSupportArgHeader header{};
|
||||||
|
std::array<IdentificationColor, 4> identification_colors{};
|
||||||
|
bool enable_explain_text{};
|
||||||
|
std::array<ExplainText, 4> explain_text{};
|
||||||
|
};
|
||||||
|
static_assert(sizeof(ControllerSupportArgOld) == 0x21C,
|
||||||
|
"ControllerSupportArgOld has incorrect size.");
|
||||||
|
|
||||||
|
// LibraryAppletVersion 0x7
|
||||||
|
struct ControllerSupportArgNew {
|
||||||
|
ControllerSupportArgHeader header{};
|
||||||
|
std::array<IdentificationColor, 8> identification_colors{};
|
||||||
|
bool enable_explain_text{};
|
||||||
|
std::array<ExplainText, 8> explain_text{};
|
||||||
|
};
|
||||||
|
static_assert(sizeof(ControllerSupportArgNew) == 0x430,
|
||||||
|
"ControllerSupportArgNew has incorrect size.");
|
||||||
|
|
||||||
|
struct ControllerSupportResultInfo {
|
||||||
|
s8 player_count{};
|
||||||
|
INSERT_PADDING_BYTES(3);
|
||||||
|
u32 selected_id{};
|
||||||
|
u32 result{};
|
||||||
|
};
|
||||||
|
static_assert(sizeof(ControllerSupportResultInfo) == 0xC,
|
||||||
|
"ControllerSupportResultInfo has incorrect size.");
|
||||||
|
|
||||||
|
class Controller final : public Applet {
|
||||||
|
public:
|
||||||
|
explicit Controller(Core::System& system_, const Core::Frontend::ControllerApplet& frontend_);
|
||||||
|
~Controller() override;
|
||||||
|
|
||||||
|
void Initialize() override;
|
||||||
|
|
||||||
|
bool TransactionComplete() const override;
|
||||||
|
ResultCode GetStatus() const override;
|
||||||
|
void ExecuteInteractive() override;
|
||||||
|
void Execute() override;
|
||||||
|
|
||||||
|
void ConfigurationComplete();
|
||||||
|
|
||||||
|
private:
|
||||||
|
const Core::Frontend::ControllerApplet& frontend;
|
||||||
|
|
||||||
|
LibraryAppletVersion library_applet_version;
|
||||||
|
ControllerSupportArgPrivate controller_private_arg;
|
||||||
|
ControllerSupportArgOld controller_user_arg_old;
|
||||||
|
ControllerSupportArgNew controller_user_arg_new;
|
||||||
|
bool complete{false};
|
||||||
|
ResultCode status{RESULT_SUCCESS};
|
||||||
|
bool is_single_mode{false};
|
||||||
|
std::vector<u8> out_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Service::AM::Applets
|
|
@ -193,7 +193,8 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
|
||||||
controller.battery_level[0] = BATTERY_FULL;
|
controller.battery_level[0] = BATTERY_FULL;
|
||||||
controller.battery_level[1] = BATTERY_FULL;
|
controller.battery_level[1] = BATTERY_FULL;
|
||||||
controller.battery_level[2] = BATTERY_FULL;
|
controller.battery_level[2] = BATTERY_FULL;
|
||||||
styleset_changed_events[controller_idx].writable->Signal();
|
|
||||||
|
SignalStyleSetChangedEvent(IndexToNPad(controller_idx));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller_NPad::OnInit() {
|
void Controller_NPad::OnInit() {
|
||||||
|
@ -518,13 +519,17 @@ void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
|
||||||
last_processed_vibration = vibrations.back();
|
last_processed_vibration = vibrations.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Controller_NPad::Vibration Controller_NPad::GetLastVibration() const {
|
||||||
|
return last_processed_vibration;
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent(u32 npad_id) const {
|
std::shared_ptr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent(u32 npad_id) const {
|
||||||
const auto& styleset_event = styleset_changed_events[NPadIdToIndex(npad_id)];
|
const auto& styleset_event = styleset_changed_events[NPadIdToIndex(npad_id)];
|
||||||
return styleset_event.readable;
|
return styleset_event.readable;
|
||||||
}
|
}
|
||||||
|
|
||||||
Controller_NPad::Vibration Controller_NPad::GetLastVibration() const {
|
void Controller_NPad::SignalStyleSetChangedEvent(u32 npad_id) const {
|
||||||
return last_processed_vibration;
|
styleset_changed_events[NPadIdToIndex(npad_id)].writable->Signal();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller_NPad::AddNewControllerAt(NPadControllerType controller, std::size_t npad_index) {
|
void Controller_NPad::AddNewControllerAt(NPadControllerType controller, std::size_t npad_index) {
|
||||||
|
@ -534,7 +539,7 @@ void Controller_NPad::AddNewControllerAt(NPadControllerType controller, std::siz
|
||||||
void Controller_NPad::UpdateControllerAt(NPadControllerType controller, std::size_t npad_index,
|
void Controller_NPad::UpdateControllerAt(NPadControllerType controller, std::size_t npad_index,
|
||||||
bool connected) {
|
bool connected) {
|
||||||
if (!connected) {
|
if (!connected) {
|
||||||
DisconnectNPad(IndexToNPad(npad_index));
|
DisconnectNPadAtIndex(npad_index);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -554,16 +559,19 @@ void Controller_NPad::UpdateControllerAt(NPadControllerType controller, std::siz
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller_NPad::DisconnectNPad(u32 npad_id) {
|
void Controller_NPad::DisconnectNPad(u32 npad_id) {
|
||||||
const auto npad_index = NPadIdToIndex(npad_id);
|
DisconnectNPadAtIndex(NPadIdToIndex(npad_id));
|
||||||
connected_controllers[npad_index].is_connected = false;
|
}
|
||||||
|
|
||||||
|
void Controller_NPad::DisconnectNPadAtIndex(std::size_t npad_index) {
|
||||||
Settings::values.players[npad_index].connected = false;
|
Settings::values.players[npad_index].connected = false;
|
||||||
|
connected_controllers[npad_index].is_connected = false;
|
||||||
|
|
||||||
auto& controller = shared_memory_entries[npad_index];
|
auto& controller = shared_memory_entries[npad_index];
|
||||||
controller.joy_styles.raw = 0; // Zero out
|
controller.joy_styles.raw = 0; // Zero out
|
||||||
controller.device_type.raw = 0;
|
controller.device_type.raw = 0;
|
||||||
controller.properties.raw = 0;
|
controller.properties.raw = 0;
|
||||||
|
|
||||||
styleset_changed_events[npad_index].writable->Signal();
|
SignalStyleSetChangedEvent(IndexToNPad(npad_index));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller_NPad::SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode) {
|
void Controller_NPad::SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode) {
|
||||||
|
@ -666,13 +674,13 @@ void Controller_NPad::ClearAllConnectedControllers() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller_NPad::DisconnectAllConnectedControllers() {
|
void Controller_NPad::DisconnectAllConnectedControllers() {
|
||||||
for (ControllerHolder& controller : connected_controllers) {
|
for (auto& controller : connected_controllers) {
|
||||||
controller.is_connected = false;
|
controller.is_connected = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller_NPad::ConnectAllDisconnectedControllers() {
|
void Controller_NPad::ConnectAllDisconnectedControllers() {
|
||||||
for (ControllerHolder& controller : connected_controllers) {
|
for (auto& controller : connected_controllers) {
|
||||||
if (controller.type != NPadControllerType::None && !controller.is_connected) {
|
if (controller.type != NPadControllerType::None && !controller.is_connected) {
|
||||||
controller.is_connected = true;
|
controller.is_connected = true;
|
||||||
}
|
}
|
||||||
|
@ -680,7 +688,7 @@ void Controller_NPad::ConnectAllDisconnectedControllers() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller_NPad::ClearAllControllers() {
|
void Controller_NPad::ClearAllControllers() {
|
||||||
for (ControllerHolder& controller : connected_controllers) {
|
for (auto& controller : connected_controllers) {
|
||||||
controller.type = NPadControllerType::None;
|
controller.type = NPadControllerType::None;
|
||||||
controller.is_connected = false;
|
controller.is_connected = false;
|
||||||
}
|
}
|
||||||
|
@ -728,92 +736,4 @@ bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Controller_NPad::NPadControllerType Controller_NPad::DecideBestController(
|
|
||||||
NPadControllerType priority) const {
|
|
||||||
if (IsControllerSupported(priority)) {
|
|
||||||
return priority;
|
|
||||||
}
|
|
||||||
const auto is_docked = Settings::values.use_docked_mode;
|
|
||||||
if (is_docked && priority == NPadControllerType::Handheld) {
|
|
||||||
priority = NPadControllerType::JoyDual;
|
|
||||||
if (IsControllerSupported(priority)) {
|
|
||||||
return priority;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
std::vector<NPadControllerType> priority_list;
|
|
||||||
switch (priority) {
|
|
||||||
case NPadControllerType::ProController:
|
|
||||||
priority_list.push_back(NPadControllerType::JoyDual);
|
|
||||||
if (!is_docked) {
|
|
||||||
priority_list.push_back(NPadControllerType::Handheld);
|
|
||||||
}
|
|
||||||
priority_list.push_back(NPadControllerType::JoyLeft);
|
|
||||||
priority_list.push_back(NPadControllerType::JoyRight);
|
|
||||||
priority_list.push_back(NPadControllerType::Pokeball);
|
|
||||||
break;
|
|
||||||
case NPadControllerType::Handheld:
|
|
||||||
priority_list.push_back(NPadControllerType::JoyDual);
|
|
||||||
priority_list.push_back(NPadControllerType::ProController);
|
|
||||||
priority_list.push_back(NPadControllerType::JoyLeft);
|
|
||||||
priority_list.push_back(NPadControllerType::JoyRight);
|
|
||||||
priority_list.push_back(NPadControllerType::Pokeball);
|
|
||||||
break;
|
|
||||||
case NPadControllerType::JoyDual:
|
|
||||||
if (!is_docked) {
|
|
||||||
priority_list.push_back(NPadControllerType::Handheld);
|
|
||||||
}
|
|
||||||
priority_list.push_back(NPadControllerType::ProController);
|
|
||||||
priority_list.push_back(NPadControllerType::JoyLeft);
|
|
||||||
priority_list.push_back(NPadControllerType::JoyRight);
|
|
||||||
priority_list.push_back(NPadControllerType::Pokeball);
|
|
||||||
break;
|
|
||||||
case NPadControllerType::JoyLeft:
|
|
||||||
priority_list.push_back(NPadControllerType::JoyRight);
|
|
||||||
priority_list.push_back(NPadControllerType::JoyDual);
|
|
||||||
if (!is_docked) {
|
|
||||||
priority_list.push_back(NPadControllerType::Handheld);
|
|
||||||
}
|
|
||||||
priority_list.push_back(NPadControllerType::ProController);
|
|
||||||
priority_list.push_back(NPadControllerType::Pokeball);
|
|
||||||
break;
|
|
||||||
case NPadControllerType::JoyRight:
|
|
||||||
priority_list.push_back(NPadControllerType::JoyLeft);
|
|
||||||
priority_list.push_back(NPadControllerType::JoyDual);
|
|
||||||
if (!is_docked) {
|
|
||||||
priority_list.push_back(NPadControllerType::Handheld);
|
|
||||||
}
|
|
||||||
priority_list.push_back(NPadControllerType::ProController);
|
|
||||||
priority_list.push_back(NPadControllerType::Pokeball);
|
|
||||||
break;
|
|
||||||
case NPadControllerType::Pokeball:
|
|
||||||
priority_list.push_back(NPadControllerType::JoyLeft);
|
|
||||||
priority_list.push_back(NPadControllerType::JoyRight);
|
|
||||||
priority_list.push_back(NPadControllerType::JoyDual);
|
|
||||||
if (!is_docked) {
|
|
||||||
priority_list.push_back(NPadControllerType::Handheld);
|
|
||||||
}
|
|
||||||
priority_list.push_back(NPadControllerType::ProController);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
priority_list.push_back(NPadControllerType::JoyDual);
|
|
||||||
if (!is_docked) {
|
|
||||||
priority_list.push_back(NPadControllerType::Handheld);
|
|
||||||
}
|
|
||||||
priority_list.push_back(NPadControllerType::ProController);
|
|
||||||
priority_list.push_back(NPadControllerType::JoyLeft);
|
|
||||||
priority_list.push_back(NPadControllerType::JoyRight);
|
|
||||||
priority_list.push_back(NPadControllerType::JoyDual);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto iter = std::find_if(priority_list.begin(), priority_list.end(),
|
|
||||||
[this](auto type) { return IsControllerSupported(type); });
|
|
||||||
if (iter == priority_list.end()) {
|
|
||||||
UNIMPLEMENTED_MSG("Could not find supported controller!");
|
|
||||||
return priority;
|
|
||||||
}
|
|
||||||
|
|
||||||
return *iter;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Service::HID
|
} // namespace Service::HID
|
||||||
|
|
|
@ -115,15 +115,19 @@ public:
|
||||||
void VibrateController(const std::vector<u32>& controller_ids,
|
void VibrateController(const std::vector<u32>& controller_ids,
|
||||||
const std::vector<Vibration>& vibrations);
|
const std::vector<Vibration>& vibrations);
|
||||||
|
|
||||||
std::shared_ptr<Kernel::ReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const;
|
|
||||||
Vibration GetLastVibration() const;
|
Vibration GetLastVibration() const;
|
||||||
|
|
||||||
|
std::shared_ptr<Kernel::ReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const;
|
||||||
|
void SignalStyleSetChangedEvent(u32 npad_id) const;
|
||||||
|
|
||||||
// Adds a new controller at an index.
|
// Adds a new controller at an index.
|
||||||
void AddNewControllerAt(NPadControllerType controller, std::size_t npad_index);
|
void AddNewControllerAt(NPadControllerType controller, std::size_t npad_index);
|
||||||
// Adds a new controller at an index with connection status.
|
// Adds a new controller at an index with connection status.
|
||||||
void UpdateControllerAt(NPadControllerType controller, std::size_t npad_index, bool connected);
|
void UpdateControllerAt(NPadControllerType controller, std::size_t npad_index, bool connected);
|
||||||
|
|
||||||
void DisconnectNPad(u32 npad_id);
|
void DisconnectNPad(u32 npad_id);
|
||||||
|
void DisconnectNPadAtIndex(std::size_t index);
|
||||||
|
|
||||||
void SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode);
|
void SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode);
|
||||||
GyroscopeZeroDriftMode GetGyroscopeZeroDriftMode() const;
|
GyroscopeZeroDriftMode GetGyroscopeZeroDriftMode() const;
|
||||||
LedPattern GetLedPattern(u32 npad_id);
|
LedPattern GetLedPattern(u32 npad_id);
|
||||||
|
@ -315,7 +319,6 @@ private:
|
||||||
|
|
||||||
void InitNewlyAddedController(std::size_t controller_idx);
|
void InitNewlyAddedController(std::size_t controller_idx);
|
||||||
bool IsControllerSupported(NPadControllerType controller) const;
|
bool IsControllerSupported(NPadControllerType controller) const;
|
||||||
NPadControllerType DecideBestController(NPadControllerType priority) const;
|
|
||||||
void RequestPadStateUpdate(u32 npad_id);
|
void RequestPadStateUpdate(u32 npad_id);
|
||||||
|
|
||||||
u32 press_state{};
|
u32 press_state{};
|
||||||
|
|
|
@ -9,6 +9,9 @@ add_executable(yuzu
|
||||||
about_dialog.cpp
|
about_dialog.cpp
|
||||||
about_dialog.h
|
about_dialog.h
|
||||||
aboutdialog.ui
|
aboutdialog.ui
|
||||||
|
applets/controller.cpp
|
||||||
|
applets/controller.h
|
||||||
|
applets/controller.ui
|
||||||
applets/error.cpp
|
applets/error.cpp
|
||||||
applets/error.h
|
applets/error.h
|
||||||
applets/profile_select.cpp
|
applets/profile_select.cpp
|
||||||
|
@ -62,12 +65,15 @@ add_executable(yuzu
|
||||||
configuration/configure_input.cpp
|
configuration/configure_input.cpp
|
||||||
configuration/configure_input.h
|
configuration/configure_input.h
|
||||||
configuration/configure_input.ui
|
configuration/configure_input.ui
|
||||||
configuration/configure_input_player.cpp
|
|
||||||
configuration/configure_input_player.h
|
|
||||||
configuration/configure_input_player.ui
|
|
||||||
configuration/configure_input_advanced.cpp
|
configuration/configure_input_advanced.cpp
|
||||||
configuration/configure_input_advanced.h
|
configuration/configure_input_advanced.h
|
||||||
configuration/configure_input_advanced.ui
|
configuration/configure_input_advanced.ui
|
||||||
|
configuration/configure_input_dialog.cpp
|
||||||
|
configuration/configure_input_dialog.h
|
||||||
|
configuration/configure_input_dialog.ui
|
||||||
|
configuration/configure_input_player.cpp
|
||||||
|
configuration/configure_input_player.h
|
||||||
|
configuration/configure_input_player.ui
|
||||||
configuration/configure_motion_touch.cpp
|
configuration/configure_motion_touch.cpp
|
||||||
configuration/configure_motion_touch.h
|
configuration/configure_motion_touch.h
|
||||||
configuration/configure_motion_touch.ui
|
configuration/configure_motion_touch.ui
|
||||||
|
|
|
@ -0,0 +1,601 @@
|
||||||
|
// Copyright 2020 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "common/assert.h"
|
||||||
|
#include "common/string_util.h"
|
||||||
|
#include "core/core.h"
|
||||||
|
#include "core/hle/lock.h"
|
||||||
|
#include "core/hle/service/hid/controllers/npad.h"
|
||||||
|
#include "core/hle/service/hid/hid.h"
|
||||||
|
#include "core/hle/service/sm/sm.h"
|
||||||
|
#include "ui_controller.h"
|
||||||
|
#include "yuzu/applets/controller.h"
|
||||||
|
#include "yuzu/configuration/configure_input_dialog.h"
|
||||||
|
#include "yuzu/main.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr std::array<std::array<bool, 4>, 8> led_patterns = {{
|
||||||
|
{1, 0, 0, 0},
|
||||||
|
{1, 1, 0, 0},
|
||||||
|
{1, 1, 1, 0},
|
||||||
|
{1, 1, 1, 1},
|
||||||
|
{1, 0, 0, 1},
|
||||||
|
{1, 0, 1, 0},
|
||||||
|
{1, 0, 1, 1},
|
||||||
|
{0, 1, 1, 0},
|
||||||
|
}};
|
||||||
|
|
||||||
|
void UpdateController(Settings::ControllerType controller_type, std::size_t npad_index,
|
||||||
|
bool connected) {
|
||||||
|
Core::System& system{Core::System::GetInstance()};
|
||||||
|
|
||||||
|
if (!system.IsPoweredOn()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Service::SM::ServiceManager& sm = system.ServiceManager();
|
||||||
|
|
||||||
|
auto& npad =
|
||||||
|
sm.GetService<Service::HID::Hid>("hid")
|
||||||
|
->GetAppletResource()
|
||||||
|
->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad);
|
||||||
|
|
||||||
|
npad.UpdateControllerAt(npad.MapSettingsTypeToNPad(controller_type), npad_index, connected);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if the given controller type is compatible with the given parameters.
|
||||||
|
bool IsControllerCompatible(Settings::ControllerType controller_type,
|
||||||
|
Core::Frontend::ControllerParameters parameters) {
|
||||||
|
switch (controller_type) {
|
||||||
|
case Settings::ControllerType::ProController:
|
||||||
|
return parameters.allow_pro_controller;
|
||||||
|
case Settings::ControllerType::DualJoyconDetached:
|
||||||
|
return parameters.allow_dual_joycons;
|
||||||
|
case Settings::ControllerType::LeftJoycon:
|
||||||
|
return parameters.allow_left_joycon;
|
||||||
|
case Settings::ControllerType::RightJoycon:
|
||||||
|
return parameters.allow_right_joycon;
|
||||||
|
case Settings::ControllerType::Handheld:
|
||||||
|
return parameters.enable_single_mode && parameters.allow_handheld;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Maps the controller type combobox index to Controller Type enum
|
||||||
|
constexpr Settings::ControllerType GetControllerTypeFromIndex(int index) {
|
||||||
|
switch (index) {
|
||||||
|
case 0:
|
||||||
|
default:
|
||||||
|
return Settings::ControllerType::ProController;
|
||||||
|
case 1:
|
||||||
|
return Settings::ControllerType::DualJoyconDetached;
|
||||||
|
case 2:
|
||||||
|
return Settings::ControllerType::LeftJoycon;
|
||||||
|
case 3:
|
||||||
|
return Settings::ControllerType::RightJoycon;
|
||||||
|
case 4:
|
||||||
|
return Settings::ControllerType::Handheld;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Maps the Controller Type enum to controller type combobox index
|
||||||
|
constexpr int GetIndexFromControllerType(Settings::ControllerType type) {
|
||||||
|
switch (type) {
|
||||||
|
case Settings::ControllerType::ProController:
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
case Settings::ControllerType::DualJoyconDetached:
|
||||||
|
return 1;
|
||||||
|
case Settings::ControllerType::LeftJoycon:
|
||||||
|
return 2;
|
||||||
|
case Settings::ControllerType::RightJoycon:
|
||||||
|
return 3;
|
||||||
|
case Settings::ControllerType::Handheld:
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
QtControllerSelectorDialog::QtControllerSelectorDialog(
|
||||||
|
QWidget* parent, Core::Frontend::ControllerParameters parameters_,
|
||||||
|
InputCommon::InputSubsystem* input_subsystem_)
|
||||||
|
: QDialog(parent), ui(std::make_unique<Ui::QtControllerSelectorDialog>()),
|
||||||
|
parameters(std::move(parameters_)), input_subsystem(input_subsystem_) {
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
player_widgets = {
|
||||||
|
ui->widgetPlayer1, ui->widgetPlayer2, ui->widgetPlayer3, ui->widgetPlayer4,
|
||||||
|
ui->widgetPlayer5, ui->widgetPlayer6, ui->widgetPlayer7, ui->widgetPlayer8,
|
||||||
|
};
|
||||||
|
|
||||||
|
player_groupboxes = {
|
||||||
|
ui->groupPlayer1Connected, ui->groupPlayer2Connected, ui->groupPlayer3Connected,
|
||||||
|
ui->groupPlayer4Connected, ui->groupPlayer5Connected, ui->groupPlayer6Connected,
|
||||||
|
ui->groupPlayer7Connected, ui->groupPlayer8Connected,
|
||||||
|
};
|
||||||
|
|
||||||
|
connected_controller_icons = {
|
||||||
|
ui->controllerPlayer1, ui->controllerPlayer2, ui->controllerPlayer3, ui->controllerPlayer4,
|
||||||
|
ui->controllerPlayer5, ui->controllerPlayer6, ui->controllerPlayer7, ui->controllerPlayer8,
|
||||||
|
};
|
||||||
|
|
||||||
|
led_patterns_boxes = {{
|
||||||
|
{ui->checkboxPlayer1LED1, ui->checkboxPlayer1LED2, ui->checkboxPlayer1LED3,
|
||||||
|
ui->checkboxPlayer1LED4},
|
||||||
|
{ui->checkboxPlayer2LED1, ui->checkboxPlayer2LED2, ui->checkboxPlayer2LED3,
|
||||||
|
ui->checkboxPlayer2LED4},
|
||||||
|
{ui->checkboxPlayer3LED1, ui->checkboxPlayer3LED2, ui->checkboxPlayer3LED3,
|
||||||
|
ui->checkboxPlayer3LED4},
|
||||||
|
{ui->checkboxPlayer4LED1, ui->checkboxPlayer4LED2, ui->checkboxPlayer4LED3,
|
||||||
|
ui->checkboxPlayer4LED4},
|
||||||
|
{ui->checkboxPlayer5LED1, ui->checkboxPlayer5LED2, ui->checkboxPlayer5LED3,
|
||||||
|
ui->checkboxPlayer5LED4},
|
||||||
|
{ui->checkboxPlayer6LED1, ui->checkboxPlayer6LED2, ui->checkboxPlayer6LED3,
|
||||||
|
ui->checkboxPlayer6LED4},
|
||||||
|
{ui->checkboxPlayer7LED1, ui->checkboxPlayer7LED2, ui->checkboxPlayer7LED3,
|
||||||
|
ui->checkboxPlayer7LED4},
|
||||||
|
{ui->checkboxPlayer8LED1, ui->checkboxPlayer8LED2, ui->checkboxPlayer8LED3,
|
||||||
|
ui->checkboxPlayer8LED4},
|
||||||
|
}};
|
||||||
|
|
||||||
|
explain_text_labels = {
|
||||||
|
ui->labelPlayer1Explain, ui->labelPlayer2Explain, ui->labelPlayer3Explain,
|
||||||
|
ui->labelPlayer4Explain, ui->labelPlayer5Explain, ui->labelPlayer6Explain,
|
||||||
|
ui->labelPlayer7Explain, ui->labelPlayer8Explain,
|
||||||
|
};
|
||||||
|
|
||||||
|
emulated_controllers = {
|
||||||
|
ui->comboPlayer1Emulated, ui->comboPlayer2Emulated, ui->comboPlayer3Emulated,
|
||||||
|
ui->comboPlayer4Emulated, ui->comboPlayer5Emulated, ui->comboPlayer6Emulated,
|
||||||
|
ui->comboPlayer7Emulated, ui->comboPlayer8Emulated,
|
||||||
|
};
|
||||||
|
|
||||||
|
player_labels = {
|
||||||
|
ui->labelPlayer1, ui->labelPlayer2, ui->labelPlayer3, ui->labelPlayer4,
|
||||||
|
ui->labelPlayer5, ui->labelPlayer6, ui->labelPlayer7, ui->labelPlayer8,
|
||||||
|
};
|
||||||
|
|
||||||
|
connected_controller_labels = {
|
||||||
|
ui->labelConnectedPlayer1, ui->labelConnectedPlayer2, ui->labelConnectedPlayer3,
|
||||||
|
ui->labelConnectedPlayer4, ui->labelConnectedPlayer5, ui->labelConnectedPlayer6,
|
||||||
|
ui->labelConnectedPlayer7, ui->labelConnectedPlayer8,
|
||||||
|
};
|
||||||
|
|
||||||
|
connected_controller_checkboxes = {
|
||||||
|
ui->checkboxPlayer1Connected, ui->checkboxPlayer2Connected, ui->checkboxPlayer3Connected,
|
||||||
|
ui->checkboxPlayer4Connected, ui->checkboxPlayer5Connected, ui->checkboxPlayer6Connected,
|
||||||
|
ui->checkboxPlayer7Connected, ui->checkboxPlayer8Connected,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Setup/load everything prior to setting up connections.
|
||||||
|
// This avoids unintentionally changing the states of elements while loading them in.
|
||||||
|
SetSupportedControllers();
|
||||||
|
DisableUnsupportedPlayers();
|
||||||
|
LoadConfiguration();
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < NUM_PLAYERS; ++i) {
|
||||||
|
SetExplainText(i);
|
||||||
|
UpdateControllerIcon(i);
|
||||||
|
UpdateLEDPattern(i);
|
||||||
|
UpdateBorderColor(i);
|
||||||
|
|
||||||
|
connect(player_groupboxes[i], &QGroupBox::toggled, [this, i](bool checked) {
|
||||||
|
if (checked) {
|
||||||
|
for (std::size_t index = 0; index <= i; ++index) {
|
||||||
|
connected_controller_checkboxes[index]->setChecked(checked);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (std::size_t index = i; index < NUM_PLAYERS; ++index) {
|
||||||
|
connected_controller_checkboxes[index]->setChecked(checked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(emulated_controllers[i], qOverload<int>(&QComboBox::currentIndexChanged),
|
||||||
|
[this, i](int) {
|
||||||
|
UpdateControllerIcon(i);
|
||||||
|
UpdateControllerState(i);
|
||||||
|
UpdateLEDPattern(i);
|
||||||
|
CheckIfParametersMet();
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(connected_controller_checkboxes[i], &QCheckBox::stateChanged, [this, i](int state) {
|
||||||
|
player_groupboxes[i]->setChecked(state == Qt::Checked);
|
||||||
|
UpdateControllerIcon(i);
|
||||||
|
UpdateControllerState(i);
|
||||||
|
UpdateLEDPattern(i);
|
||||||
|
UpdateBorderColor(i);
|
||||||
|
CheckIfParametersMet();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (i == 0) {
|
||||||
|
connect(emulated_controllers[i], qOverload<int>(&QComboBox::currentIndexChanged),
|
||||||
|
[this](int index) {
|
||||||
|
UpdateDockedState(GetControllerTypeFromIndex(index) ==
|
||||||
|
Settings::ControllerType::Handheld);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(ui->inputConfigButton, &QPushButton::clicked, this,
|
||||||
|
&QtControllerSelectorDialog::CallConfigureInputDialog);
|
||||||
|
|
||||||
|
connect(ui->buttonBox, &QDialogButtonBox::accepted, this,
|
||||||
|
&QtControllerSelectorDialog::ApplyConfiguration);
|
||||||
|
|
||||||
|
// If keep_controllers_connected is false, forcefully disconnect all controllers
|
||||||
|
if (!parameters.keep_controllers_connected) {
|
||||||
|
for (auto player : player_groupboxes) {
|
||||||
|
player->setChecked(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckIfParametersMet();
|
||||||
|
|
||||||
|
resize(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
QtControllerSelectorDialog::~QtControllerSelectorDialog() = default;
|
||||||
|
|
||||||
|
void QtControllerSelectorDialog::ApplyConfiguration() {
|
||||||
|
// Update the controller state once more, just to be sure they are properly applied.
|
||||||
|
for (std::size_t index = 0; index < NUM_PLAYERS; ++index) {
|
||||||
|
UpdateControllerState(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool pre_docked_mode = Settings::values.use_docked_mode;
|
||||||
|
Settings::values.use_docked_mode = ui->radioDocked->isChecked();
|
||||||
|
OnDockedModeChanged(pre_docked_mode, Settings::values.use_docked_mode);
|
||||||
|
|
||||||
|
Settings::values.vibration_enabled = ui->vibrationGroup->isChecked();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtControllerSelectorDialog::LoadConfiguration() {
|
||||||
|
for (std::size_t index = 0; index < NUM_PLAYERS; ++index) {
|
||||||
|
const auto connected = Settings::values.players[index].connected ||
|
||||||
|
(index == 0 && Settings::values.players[8].connected);
|
||||||
|
player_groupboxes[index]->setChecked(connected);
|
||||||
|
connected_controller_checkboxes[index]->setChecked(connected);
|
||||||
|
emulated_controllers[index]->setCurrentIndex(
|
||||||
|
GetIndexFromControllerType(Settings::values.players[index].controller_type));
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateDockedState(Settings::values.players[8].connected);
|
||||||
|
|
||||||
|
ui->vibrationGroup->setChecked(Settings::values.vibration_enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtControllerSelectorDialog::CallConfigureInputDialog() {
|
||||||
|
const auto max_supported_players = parameters.enable_single_mode ? 1 : parameters.max_players;
|
||||||
|
|
||||||
|
ConfigureInputDialog dialog(this, max_supported_players, input_subsystem);
|
||||||
|
|
||||||
|
dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
|
||||||
|
Qt::WindowSystemMenuHint);
|
||||||
|
dialog.setWindowModality(Qt::WindowModal);
|
||||||
|
dialog.exec();
|
||||||
|
|
||||||
|
dialog.ApplyConfiguration();
|
||||||
|
|
||||||
|
LoadConfiguration();
|
||||||
|
CheckIfParametersMet();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtControllerSelectorDialog::CheckIfParametersMet() {
|
||||||
|
// Here, we check and validate the current configuration against all applicable parameters.
|
||||||
|
const auto num_connected_players = static_cast<int>(
|
||||||
|
std::count_if(player_groupboxes.begin(), player_groupboxes.end(),
|
||||||
|
[this](const QGroupBox* player) { return player->isChecked(); }));
|
||||||
|
|
||||||
|
const auto min_supported_players = parameters.enable_single_mode ? 1 : parameters.min_players;
|
||||||
|
const auto max_supported_players = parameters.enable_single_mode ? 1 : parameters.max_players;
|
||||||
|
|
||||||
|
// First, check against the number of connected players.
|
||||||
|
if (num_connected_players < min_supported_players ||
|
||||||
|
num_connected_players > max_supported_players) {
|
||||||
|
parameters_met = false;
|
||||||
|
ui->buttonBox->setEnabled(parameters_met);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next, check against all connected controllers.
|
||||||
|
const auto all_controllers_compatible = [this] {
|
||||||
|
for (std::size_t index = 0; index < NUM_PLAYERS; ++index) {
|
||||||
|
// Skip controllers that are not used, we only care about the currently connected ones.
|
||||||
|
if (!player_groupboxes[index]->isChecked() || !player_groupboxes[index]->isEnabled()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto compatible = IsControllerCompatible(
|
||||||
|
GetControllerTypeFromIndex(emulated_controllers[index]->currentIndex()),
|
||||||
|
parameters);
|
||||||
|
|
||||||
|
// If any controller is found to be incompatible, return false early.
|
||||||
|
if (!compatible) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reaching here means all currently connected controllers are compatible.
|
||||||
|
return true;
|
||||||
|
}();
|
||||||
|
|
||||||
|
if (!all_controllers_compatible) {
|
||||||
|
parameters_met = false;
|
||||||
|
ui->buttonBox->setEnabled(parameters_met);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
parameters_met = true;
|
||||||
|
ui->buttonBox->setEnabled(parameters_met);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtControllerSelectorDialog::SetSupportedControllers() {
|
||||||
|
const QString theme = [this] {
|
||||||
|
if (QIcon::themeName().contains(QStringLiteral("dark"))) {
|
||||||
|
return QStringLiteral("_dark");
|
||||||
|
} else if (QIcon::themeName().contains(QStringLiteral("midnight"))) {
|
||||||
|
return QStringLiteral("_midnight");
|
||||||
|
} else {
|
||||||
|
return QString{};
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
|
if (parameters.enable_single_mode && parameters.allow_handheld) {
|
||||||
|
ui->controllerSupported1->setStyleSheet(
|
||||||
|
QStringLiteral("image: url(:/controller/applet_handheld%0); ").arg(theme));
|
||||||
|
} else {
|
||||||
|
ui->controllerSupported1->setStyleSheet(
|
||||||
|
QStringLiteral("image: url(:/controller/applet_handheld%0_disabled); ").arg(theme));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parameters.allow_dual_joycons) {
|
||||||
|
ui->controllerSupported2->setStyleSheet(
|
||||||
|
QStringLiteral("image: url(:/controller/applet_dual_joycon%0); ").arg(theme));
|
||||||
|
} else {
|
||||||
|
ui->controllerSupported2->setStyleSheet(
|
||||||
|
QStringLiteral("image: url(:/controller/applet_dual_joycon%0_disabled); ").arg(theme));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parameters.allow_left_joycon) {
|
||||||
|
ui->controllerSupported3->setStyleSheet(
|
||||||
|
QStringLiteral("image: url(:/controller/applet_joycon_left%0); ").arg(theme));
|
||||||
|
} else {
|
||||||
|
ui->controllerSupported3->setStyleSheet(
|
||||||
|
QStringLiteral("image: url(:/controller/applet_joycon_left%0_disabled); ").arg(theme));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parameters.allow_right_joycon) {
|
||||||
|
ui->controllerSupported4->setStyleSheet(
|
||||||
|
QStringLiteral("image: url(:/controller/applet_joycon_right%0); ").arg(theme));
|
||||||
|
} else {
|
||||||
|
ui->controllerSupported4->setStyleSheet(
|
||||||
|
QStringLiteral("image: url(:/controller/applet_joycon_right%0_disabled); ").arg(theme));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parameters.allow_pro_controller) {
|
||||||
|
ui->controllerSupported5->setStyleSheet(
|
||||||
|
QStringLiteral("image: url(:/controller/applet_pro_controller%0); ").arg(theme));
|
||||||
|
} else {
|
||||||
|
ui->controllerSupported5->setStyleSheet(
|
||||||
|
QStringLiteral("image: url(:/controller/applet_pro_controller%0_disabled); ")
|
||||||
|
.arg(theme));
|
||||||
|
}
|
||||||
|
|
||||||
|
// enable_single_mode overrides min_players and max_players.
|
||||||
|
if (parameters.enable_single_mode) {
|
||||||
|
ui->numberSupportedLabel->setText(QStringLiteral("1"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parameters.min_players == parameters.max_players) {
|
||||||
|
ui->numberSupportedLabel->setText(QStringLiteral("%1").arg(parameters.max_players));
|
||||||
|
} else {
|
||||||
|
ui->numberSupportedLabel->setText(
|
||||||
|
QStringLiteral("%1 - %2").arg(parameters.min_players).arg(parameters.max_players));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index) {
|
||||||
|
if (!player_groupboxes[player_index]->isChecked()) {
|
||||||
|
connected_controller_icons[player_index]->setStyleSheet(QString{});
|
||||||
|
player_labels[player_index]->show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString stylesheet = [this, player_index] {
|
||||||
|
switch (GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex())) {
|
||||||
|
case Settings::ControllerType::ProController:
|
||||||
|
return QStringLiteral("image: url(:/controller/applet_pro_controller%0); ");
|
||||||
|
case Settings::ControllerType::DualJoyconDetached:
|
||||||
|
return QStringLiteral("image: url(:/controller/applet_dual_joycon%0); ");
|
||||||
|
case Settings::ControllerType::LeftJoycon:
|
||||||
|
return QStringLiteral("image: url(:/controller/applet_joycon_left%0); ");
|
||||||
|
case Settings::ControllerType::RightJoycon:
|
||||||
|
return QStringLiteral("image: url(:/controller/applet_joycon_right%0); ");
|
||||||
|
case Settings::ControllerType::Handheld:
|
||||||
|
return QStringLiteral("image: url(:/controller/applet_handheld%0); ");
|
||||||
|
default:
|
||||||
|
return QString{};
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
|
const QString theme = [this] {
|
||||||
|
if (QIcon::themeName().contains(QStringLiteral("dark"))) {
|
||||||
|
return QStringLiteral("_dark");
|
||||||
|
} else if (QIcon::themeName().contains(QStringLiteral("midnight"))) {
|
||||||
|
return QStringLiteral("_midnight");
|
||||||
|
} else {
|
||||||
|
return QString{};
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
|
connected_controller_icons[player_index]->setStyleSheet(stylesheet.arg(theme));
|
||||||
|
player_labels[player_index]->hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtControllerSelectorDialog::UpdateControllerState(std::size_t player_index) {
|
||||||
|
auto& player = Settings::values.players[player_index];
|
||||||
|
|
||||||
|
player.controller_type =
|
||||||
|
GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex());
|
||||||
|
player.connected = player_groupboxes[player_index]->isChecked();
|
||||||
|
|
||||||
|
// Player 2-8
|
||||||
|
if (player_index != 0) {
|
||||||
|
UpdateController(player.controller_type, player_index, player.connected);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Player 1 and Handheld
|
||||||
|
auto& handheld = Settings::values.players[8];
|
||||||
|
// If Handheld is selected, copy all the settings from Player 1 to Handheld.
|
||||||
|
if (player.controller_type == Settings::ControllerType::Handheld) {
|
||||||
|
handheld = player;
|
||||||
|
handheld.connected = player_groupboxes[player_index]->isChecked();
|
||||||
|
player.connected = false; // Disconnect Player 1
|
||||||
|
} else {
|
||||||
|
player.connected = player_groupboxes[player_index]->isChecked();
|
||||||
|
handheld.connected = false; // Disconnect Handheld
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateController(player.controller_type, player_index, player.connected);
|
||||||
|
UpdateController(Settings::ControllerType::Handheld, 8, handheld.connected);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtControllerSelectorDialog::UpdateLEDPattern(std::size_t player_index) {
|
||||||
|
if (!player_groupboxes[player_index]->isChecked() ||
|
||||||
|
GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex()) ==
|
||||||
|
Settings::ControllerType::Handheld) {
|
||||||
|
led_patterns_boxes[player_index][0]->setChecked(false);
|
||||||
|
led_patterns_boxes[player_index][1]->setChecked(false);
|
||||||
|
led_patterns_boxes[player_index][2]->setChecked(false);
|
||||||
|
led_patterns_boxes[player_index][3]->setChecked(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
led_patterns_boxes[player_index][0]->setChecked(led_patterns[player_index][0]);
|
||||||
|
led_patterns_boxes[player_index][1]->setChecked(led_patterns[player_index][1]);
|
||||||
|
led_patterns_boxes[player_index][2]->setChecked(led_patterns[player_index][2]);
|
||||||
|
led_patterns_boxes[player_index][3]->setChecked(led_patterns[player_index][3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtControllerSelectorDialog::UpdateBorderColor(std::size_t player_index) {
|
||||||
|
if (!parameters.enable_border_color ||
|
||||||
|
player_index >= static_cast<std::size_t>(parameters.max_players) ||
|
||||||
|
player_groupboxes[player_index]->styleSheet().contains(QStringLiteral("QGroupBox"))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
player_groupboxes[player_index]->setStyleSheet(
|
||||||
|
player_groupboxes[player_index]->styleSheet().append(
|
||||||
|
QStringLiteral("QGroupBox#groupPlayer%1Connected:checked "
|
||||||
|
"{ border: 1px solid rgba(%2, %3, %4, %5); }")
|
||||||
|
.arg(player_index + 1)
|
||||||
|
.arg(parameters.border_colors[player_index][0])
|
||||||
|
.arg(parameters.border_colors[player_index][1])
|
||||||
|
.arg(parameters.border_colors[player_index][2])
|
||||||
|
.arg(parameters.border_colors[player_index][3])));
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtControllerSelectorDialog::SetExplainText(std::size_t player_index) {
|
||||||
|
if (!parameters.enable_explain_text ||
|
||||||
|
player_index >= static_cast<std::size_t>(parameters.max_players)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
explain_text_labels[player_index]->setText(QString::fromStdString(
|
||||||
|
Common::StringFromFixedZeroTerminatedBuffer(parameters.explain_text[player_index].data(),
|
||||||
|
parameters.explain_text[player_index].size())));
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtControllerSelectorDialog::UpdateDockedState(bool is_handheld) {
|
||||||
|
// Disallow changing the console mode if the controller type is handheld.
|
||||||
|
ui->radioDocked->setEnabled(!is_handheld);
|
||||||
|
ui->radioUndocked->setEnabled(!is_handheld);
|
||||||
|
|
||||||
|
ui->radioDocked->setChecked(Settings::values.use_docked_mode);
|
||||||
|
ui->radioUndocked->setChecked(!Settings::values.use_docked_mode);
|
||||||
|
|
||||||
|
// Also force into undocked mode if the controller type is handheld.
|
||||||
|
if (is_handheld) {
|
||||||
|
ui->radioUndocked->setChecked(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtControllerSelectorDialog::DisableUnsupportedPlayers() {
|
||||||
|
const auto max_supported_players = parameters.enable_single_mode ? 1 : parameters.max_players;
|
||||||
|
|
||||||
|
switch (max_supported_players) {
|
||||||
|
case 0:
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
|
return;
|
||||||
|
case 1:
|
||||||
|
ui->widgetSpacer->hide();
|
||||||
|
ui->widgetSpacer2->hide();
|
||||||
|
ui->widgetSpacer3->hide();
|
||||||
|
ui->widgetSpacer4->hide();
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
ui->widgetSpacer->hide();
|
||||||
|
ui->widgetSpacer2->hide();
|
||||||
|
ui->widgetSpacer3->hide();
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
ui->widgetSpacer->hide();
|
||||||
|
ui->widgetSpacer2->hide();
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
ui->widgetSpacer->hide();
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
case 6:
|
||||||
|
case 7:
|
||||||
|
case 8:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::size_t index = max_supported_players; index < NUM_PLAYERS; ++index) {
|
||||||
|
// Disconnect any unsupported players here and disable or hide them if applicable.
|
||||||
|
Settings::values.players[index].connected = false;
|
||||||
|
UpdateController(Settings::values.players[index].controller_type, index, false);
|
||||||
|
// Hide the player widgets when max_supported_controllers is less than or equal to 4.
|
||||||
|
if (max_supported_players <= 4) {
|
||||||
|
player_widgets[index]->hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable and hide the following to prevent these from interaction.
|
||||||
|
player_widgets[index]->setDisabled(true);
|
||||||
|
connected_controller_checkboxes[index]->setDisabled(true);
|
||||||
|
connected_controller_labels[index]->hide();
|
||||||
|
connected_controller_checkboxes[index]->hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QtControllerSelector::QtControllerSelector(GMainWindow& parent) {
|
||||||
|
connect(this, &QtControllerSelector::MainWindowReconfigureControllers, &parent,
|
||||||
|
&GMainWindow::ControllerSelectorReconfigureControllers, Qt::QueuedConnection);
|
||||||
|
connect(&parent, &GMainWindow::ControllerSelectorReconfigureFinished, this,
|
||||||
|
&QtControllerSelector::MainWindowReconfigureFinished, Qt::QueuedConnection);
|
||||||
|
}
|
||||||
|
|
||||||
|
QtControllerSelector::~QtControllerSelector() = default;
|
||||||
|
|
||||||
|
void QtControllerSelector::ReconfigureControllers(
|
||||||
|
std::function<void()> callback, Core::Frontend::ControllerParameters parameters) const {
|
||||||
|
this->callback = std::move(callback);
|
||||||
|
emit MainWindowReconfigureControllers(parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtControllerSelector::MainWindowReconfigureFinished() {
|
||||||
|
// Acquire the HLE mutex
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
|
||||||
|
callback();
|
||||||
|
}
|
|
@ -0,0 +1,133 @@
|
||||||
|
// Copyright 2020 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <memory>
|
||||||
|
#include <QDialog>
|
||||||
|
#include "core/frontend/applets/controller.h"
|
||||||
|
|
||||||
|
class GMainWindow;
|
||||||
|
class QCheckBox;
|
||||||
|
class QComboBox;
|
||||||
|
class QDialogButtonBox;
|
||||||
|
class QGroupBox;
|
||||||
|
class QLabel;
|
||||||
|
|
||||||
|
namespace InputCommon {
|
||||||
|
class InputSubsystem;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class QtControllerSelectorDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
class QtControllerSelectorDialog final : public QDialog {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit QtControllerSelectorDialog(QWidget* parent,
|
||||||
|
Core::Frontend::ControllerParameters parameters_,
|
||||||
|
InputCommon::InputSubsystem* input_subsystem_);
|
||||||
|
~QtControllerSelectorDialog() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Applies the current configuration.
|
||||||
|
void ApplyConfiguration();
|
||||||
|
|
||||||
|
// Loads the current input configuration into the frontend applet.
|
||||||
|
void LoadConfiguration();
|
||||||
|
|
||||||
|
// Initializes the "Configure Input" Dialog.
|
||||||
|
void CallConfigureInputDialog();
|
||||||
|
|
||||||
|
// Checks the current configuration against the given parameters and
|
||||||
|
// sets the value of parameters_met.
|
||||||
|
void CheckIfParametersMet();
|
||||||
|
|
||||||
|
// Sets the controller icons for "Supported Controller Types".
|
||||||
|
void SetSupportedControllers();
|
||||||
|
|
||||||
|
// Updates the controller icons per player.
|
||||||
|
void UpdateControllerIcon(std::size_t player_index);
|
||||||
|
|
||||||
|
// Updates the controller state (type and connection status) per player.
|
||||||
|
void UpdateControllerState(std::size_t player_index);
|
||||||
|
|
||||||
|
// Updates the LED pattern per player.
|
||||||
|
void UpdateLEDPattern(std::size_t player_index);
|
||||||
|
|
||||||
|
// Updates the border color per player.
|
||||||
|
void UpdateBorderColor(std::size_t player_index);
|
||||||
|
|
||||||
|
// Sets the "Explain Text" per player.
|
||||||
|
void SetExplainText(std::size_t player_index);
|
||||||
|
|
||||||
|
// Updates the console mode.
|
||||||
|
void UpdateDockedState(bool is_handheld);
|
||||||
|
|
||||||
|
// Disables and disconnects unsupported players based on the given parameters.
|
||||||
|
void DisableUnsupportedPlayers();
|
||||||
|
|
||||||
|
std::unique_ptr<Ui::QtControllerSelectorDialog> ui;
|
||||||
|
|
||||||
|
// Parameters sent in from the backend HLE applet.
|
||||||
|
Core::Frontend::ControllerParameters parameters;
|
||||||
|
|
||||||
|
InputCommon::InputSubsystem* input_subsystem;
|
||||||
|
|
||||||
|
// This is true if and only if all parameters are met. Otherwise, this is false.
|
||||||
|
// This determines whether the "OK" button can be clicked to exit the applet.
|
||||||
|
bool parameters_met{false};
|
||||||
|
|
||||||
|
static constexpr std::size_t NUM_PLAYERS = 8;
|
||||||
|
|
||||||
|
// Widgets encapsulating the groupboxes and comboboxes per player.
|
||||||
|
std::array<QWidget*, NUM_PLAYERS> player_widgets;
|
||||||
|
|
||||||
|
// Groupboxes encapsulating the controller icons and LED patterns per player.
|
||||||
|
std::array<QGroupBox*, NUM_PLAYERS> player_groupboxes;
|
||||||
|
|
||||||
|
// Icons for currently connected controllers/players.
|
||||||
|
std::array<QWidget*, NUM_PLAYERS> connected_controller_icons;
|
||||||
|
|
||||||
|
// Labels that represent the player numbers in place of the controller icons.
|
||||||
|
std::array<QLabel*, NUM_PLAYERS> player_labels;
|
||||||
|
|
||||||
|
// LED patterns for currently connected controllers/players.
|
||||||
|
std::array<std::array<QCheckBox*, 4>, NUM_PLAYERS> led_patterns_boxes;
|
||||||
|
|
||||||
|
// Labels representing additional information known as "Explain Text" per player.
|
||||||
|
std::array<QLabel*, NUM_PLAYERS> explain_text_labels;
|
||||||
|
|
||||||
|
// Comboboxes with a list of emulated controllers per player.
|
||||||
|
std::array<QComboBox*, NUM_PLAYERS> emulated_controllers;
|
||||||
|
|
||||||
|
// Labels representing the number of connected controllers
|
||||||
|
// above the "Connected Controllers" checkboxes.
|
||||||
|
std::array<QLabel*, NUM_PLAYERS> connected_controller_labels;
|
||||||
|
|
||||||
|
// Checkboxes representing the "Connected Controllers".
|
||||||
|
std::array<QCheckBox*, NUM_PLAYERS> connected_controller_checkboxes;
|
||||||
|
};
|
||||||
|
|
||||||
|
class QtControllerSelector final : public QObject, public Core::Frontend::ControllerApplet {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit QtControllerSelector(GMainWindow& parent);
|
||||||
|
~QtControllerSelector() override;
|
||||||
|
|
||||||
|
void ReconfigureControllers(std::function<void()> callback,
|
||||||
|
Core::Frontend::ControllerParameters parameters) const override;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void MainWindowReconfigureControllers(Core::Frontend::ControllerParameters parameters) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void MainWindowReconfigureFinished();
|
||||||
|
|
||||||
|
mutable std::function<void()> callback;
|
||||||
|
};
|
|
@ -70,7 +70,8 @@ ConfigureInput::ConfigureInput(QWidget* parent)
|
||||||
|
|
||||||
ConfigureInput::~ConfigureInput() = default;
|
ConfigureInput::~ConfigureInput() = default;
|
||||||
|
|
||||||
void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem) {
|
void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem,
|
||||||
|
std::size_t max_players) {
|
||||||
player_controllers = {
|
player_controllers = {
|
||||||
new ConfigureInputPlayer(this, 0, ui->consoleInputSettings, input_subsystem),
|
new ConfigureInputPlayer(this, 0, ui->consoleInputSettings, input_subsystem),
|
||||||
new ConfigureInputPlayer(this, 1, ui->consoleInputSettings, input_subsystem),
|
new ConfigureInputPlayer(this, 1, ui->consoleInputSettings, input_subsystem),
|
||||||
|
@ -93,6 +94,11 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem) {
|
||||||
ui->checkboxPlayer7Connected, ui->checkboxPlayer8Connected,
|
ui->checkboxPlayer7Connected, ui->checkboxPlayer8Connected,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::array<QLabel*, 8> player_connected_labels = {
|
||||||
|
ui->label, ui->label_3, ui->label_4, ui->label_5,
|
||||||
|
ui->label_6, ui->label_7, ui->label_8, ui->label_9,
|
||||||
|
};
|
||||||
|
|
||||||
for (std::size_t i = 0; i < player_tabs.size(); ++i) {
|
for (std::size_t i = 0; i < player_tabs.size(); ++i) {
|
||||||
player_tabs[i]->setLayout(new QHBoxLayout(player_tabs[i]));
|
player_tabs[i]->setLayout(new QHBoxLayout(player_tabs[i]));
|
||||||
player_tabs[i]->layout()->addWidget(player_controllers[i]);
|
player_tabs[i]->layout()->addWidget(player_controllers[i]);
|
||||||
|
@ -112,6 +118,13 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem) {
|
||||||
connect(player_connected[i], &QCheckBox::stateChanged, [this, i](int state) {
|
connect(player_connected[i], &QCheckBox::stateChanged, [this, i](int state) {
|
||||||
player_controllers[i]->ConnectPlayer(state == Qt::Checked);
|
player_controllers[i]->ConnectPlayer(state == Qt::Checked);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Remove/hide all the elements that exceed max_players, if applicable.
|
||||||
|
if (i >= max_players) {
|
||||||
|
ui->tabWidget->removeTab(static_cast<int>(max_players));
|
||||||
|
player_connected[i]->hide();
|
||||||
|
player_connected_labels[i]->hide();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Only the first player can choose handheld mode so connect the signal just to player 1
|
// Only the first player can choose handheld mode so connect the signal just to player 1
|
||||||
connect(player_controllers[0], &ConfigureInputPlayer::HandheldStateChanged,
|
connect(player_controllers[0], &ConfigureInputPlayer::HandheldStateChanged,
|
||||||
|
@ -175,8 +188,7 @@ void ConfigureInput::RetranslateUI() {
|
||||||
|
|
||||||
void ConfigureInput::LoadConfiguration() {
|
void ConfigureInput::LoadConfiguration() {
|
||||||
LoadPlayerControllerIndices();
|
LoadPlayerControllerIndices();
|
||||||
UpdateDockedState(Settings::values.players[0].controller_type ==
|
UpdateDockedState(Settings::values.players[8].connected);
|
||||||
Settings::ControllerType::Handheld);
|
|
||||||
|
|
||||||
ui->vibrationGroup->setChecked(Settings::values.vibration_enabled);
|
ui->vibrationGroup->setChecked(Settings::values.vibration_enabled);
|
||||||
}
|
}
|
||||||
|
@ -208,14 +220,14 @@ void ConfigureInput::RestoreDefaults() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureInput::UpdateDockedState(bool is_handheld) {
|
void ConfigureInput::UpdateDockedState(bool is_handheld) {
|
||||||
// If the controller type is handheld only, disallow changing docked mode
|
// Disallow changing the console mode if the controller type is handheld.
|
||||||
ui->radioDocked->setEnabled(!is_handheld);
|
ui->radioDocked->setEnabled(!is_handheld);
|
||||||
ui->radioUndocked->setEnabled(!is_handheld);
|
ui->radioUndocked->setEnabled(!is_handheld);
|
||||||
|
|
||||||
ui->radioDocked->setChecked(Settings::values.use_docked_mode);
|
ui->radioDocked->setChecked(Settings::values.use_docked_mode);
|
||||||
ui->radioUndocked->setChecked(!Settings::values.use_docked_mode);
|
ui->radioUndocked->setChecked(!Settings::values.use_docked_mode);
|
||||||
|
|
||||||
// If its handheld only, force docked mode off (since you can't play handheld in a dock)
|
// Also force into undocked mode if the controller type is handheld.
|
||||||
if (is_handheld) {
|
if (is_handheld) {
|
||||||
ui->radioUndocked->setChecked(true);
|
ui->radioUndocked->setChecked(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ public:
|
||||||
~ConfigureInput() override;
|
~ConfigureInput() override;
|
||||||
|
|
||||||
/// Initializes the input dialog with the given input subsystem.
|
/// Initializes the input dialog with the given input subsystem.
|
||||||
void Initialize(InputCommon::InputSubsystem* input_subsystem_);
|
void Initialize(InputCommon::InputSubsystem* input_subsystem_, std::size_t max_players = 8);
|
||||||
|
|
||||||
/// Save all button configurations to settings file.
|
/// Save all button configurations to settings file.
|
||||||
void ApplyConfiguration();
|
void ApplyConfiguration();
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
// Copyright 2020 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "ui_configure_input_dialog.h"
|
||||||
|
#include "yuzu/configuration/configure_input_dialog.h"
|
||||||
|
|
||||||
|
ConfigureInputDialog::ConfigureInputDialog(QWidget* parent, std::size_t max_players,
|
||||||
|
InputCommon::InputSubsystem* input_subsystem)
|
||||||
|
: QDialog(parent), ui(std::make_unique<Ui::ConfigureInputDialog>()),
|
||||||
|
input_widget(new ConfigureInput(this)) {
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
input_widget->Initialize(input_subsystem, max_players);
|
||||||
|
|
||||||
|
ui->inputLayout->addWidget(input_widget);
|
||||||
|
|
||||||
|
RetranslateUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigureInputDialog::~ConfigureInputDialog() = default;
|
||||||
|
|
||||||
|
void ConfigureInputDialog::ApplyConfiguration() {
|
||||||
|
input_widget->ApplyConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigureInputDialog::changeEvent(QEvent* event) {
|
||||||
|
if (event->type() == QEvent::LanguageChange) {
|
||||||
|
RetranslateUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
QDialog::changeEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigureInputDialog::RetranslateUI() {
|
||||||
|
ui->retranslateUi(this);
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
// Copyright 2020 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <QDialog>
|
||||||
|
#include "yuzu/configuration/configure_input.h"
|
||||||
|
|
||||||
|
class QPushButton;
|
||||||
|
|
||||||
|
namespace InputCommon {
|
||||||
|
class InputSubsystem;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class ConfigureInputDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ConfigureInputDialog : public QDialog {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ConfigureInputDialog(QWidget* parent, std::size_t max_players,
|
||||||
|
InputCommon::InputSubsystem* input_subsystem);
|
||||||
|
~ConfigureInputDialog() override;
|
||||||
|
|
||||||
|
void ApplyConfiguration();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void changeEvent(QEvent* event) override;
|
||||||
|
void RetranslateUI();
|
||||||
|
|
||||||
|
std::unique_ptr<Ui::ConfigureInputDialog> ui;
|
||||||
|
|
||||||
|
ConfigureInput* input_widget;
|
||||||
|
};
|
|
@ -0,0 +1,57 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>ConfigureInputDialog</class>
|
||||||
|
<widget class="QDialog" name="ConfigureInputDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>70</width>
|
||||||
|
<height>540</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Configure Input</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>9</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>9</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>9</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>9</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="inputLayout"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>ConfigureInputDialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
|
@ -11,6 +11,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// VFS includes must be before glad as they will conflict with Windows file api, which uses defines.
|
// VFS includes must be before glad as they will conflict with Windows file api, which uses defines.
|
||||||
|
#include "applets/controller.h"
|
||||||
#include "applets/error.h"
|
#include "applets/error.h"
|
||||||
#include "applets/profile_select.h"
|
#include "applets/profile_select.h"
|
||||||
#include "applets/software_keyboard.h"
|
#include "applets/software_keyboard.h"
|
||||||
|
@ -19,7 +20,9 @@
|
||||||
#include "configuration/configure_per_game.h"
|
#include "configuration/configure_per_game.h"
|
||||||
#include "core/file_sys/vfs.h"
|
#include "core/file_sys/vfs.h"
|
||||||
#include "core/file_sys/vfs_real.h"
|
#include "core/file_sys/vfs_real.h"
|
||||||
|
#include "core/frontend/applets/controller.h"
|
||||||
#include "core/frontend/applets/general_frontend.h"
|
#include "core/frontend/applets/general_frontend.h"
|
||||||
|
#include "core/frontend/applets/software_keyboard.h"
|
||||||
#include "core/hle/service/acc/profile_manager.h"
|
#include "core/hle/service/acc/profile_manager.h"
|
||||||
#include "core/hle/service/am/applet_ae.h"
|
#include "core/hle/service/am/applet_ae.h"
|
||||||
#include "core/hle/service/am/applet_oe.h"
|
#include "core/hle/service/am/applet_oe.h"
|
||||||
|
@ -84,7 +87,6 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
|
||||||
#include "core/file_sys/romfs.h"
|
#include "core/file_sys/romfs.h"
|
||||||
#include "core/file_sys/savedata_factory.h"
|
#include "core/file_sys/savedata_factory.h"
|
||||||
#include "core/file_sys/submission_package.h"
|
#include "core/file_sys/submission_package.h"
|
||||||
#include "core/frontend/applets/software_keyboard.h"
|
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/hle/service/am/am.h"
|
#include "core/hle/service/am/am.h"
|
||||||
#include "core/hle/service/filesystem/filesystem.h"
|
#include "core/hle/service/filesystem/filesystem.h"
|
||||||
|
@ -283,6 +285,23 @@ GMainWindow::~GMainWindow() {
|
||||||
delete render_window;
|
delete render_window;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GMainWindow::ControllerSelectorReconfigureControllers(
|
||||||
|
const Core::Frontend::ControllerParameters& parameters) {
|
||||||
|
QtControllerSelectorDialog dialog(this, parameters, input_subsystem.get());
|
||||||
|
dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
|
||||||
|
Qt::WindowSystemMenuHint);
|
||||||
|
dialog.setWindowModality(Qt::WindowModal);
|
||||||
|
dialog.exec();
|
||||||
|
|
||||||
|
emit ControllerSelectorReconfigureFinished();
|
||||||
|
|
||||||
|
// Don't forget to apply settings.
|
||||||
|
Settings::Apply();
|
||||||
|
config->Save();
|
||||||
|
|
||||||
|
UpdateStatusButtons();
|
||||||
|
}
|
||||||
|
|
||||||
void GMainWindow::ProfileSelectorSelectProfile() {
|
void GMainWindow::ProfileSelectorSelectProfile() {
|
||||||
const Service::Account::ProfileManager manager;
|
const Service::Account::ProfileManager manager;
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
@ -291,10 +310,12 @@ void GMainWindow::ProfileSelectorSelectProfile() {
|
||||||
dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
|
dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
|
||||||
Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);
|
Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);
|
||||||
dialog.setWindowModality(Qt::WindowModal);
|
dialog.setWindowModality(Qt::WindowModal);
|
||||||
|
|
||||||
if (dialog.exec() == QDialog::Rejected) {
|
if (dialog.exec() == QDialog::Rejected) {
|
||||||
emit ProfileSelectorFinishedSelection(std::nullopt);
|
emit ProfileSelectorFinishedSelection(std::nullopt);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
index = dialog.GetIndex();
|
index = dialog.GetIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -966,13 +987,14 @@ bool GMainWindow::LoadROM(const QString& filename) {
|
||||||
system.SetFilesystem(vfs);
|
system.SetFilesystem(vfs);
|
||||||
|
|
||||||
system.SetAppletFrontendSet({
|
system.SetAppletFrontendSet({
|
||||||
nullptr, // Parental Controls
|
std::make_unique<QtControllerSelector>(*this), // Controller Selector
|
||||||
std::make_unique<QtErrorDisplay>(*this), //
|
nullptr, // E-Commerce
|
||||||
nullptr, // Photo Viewer
|
std::make_unique<QtErrorDisplay>(*this), // Error Display
|
||||||
std::make_unique<QtProfileSelector>(*this), //
|
nullptr, // Parental Controls
|
||||||
std::make_unique<QtSoftwareKeyboard>(*this), //
|
nullptr, // Photo Viewer
|
||||||
std::make_unique<QtWebBrowser>(*this), //
|
std::make_unique<QtProfileSelector>(*this), // Profile Selector
|
||||||
nullptr, // E-Commerce
|
std::make_unique<QtSoftwareKeyboard>(*this), // Software Keyboard
|
||||||
|
std::make_unique<QtWebBrowser>(*this), // Web Browser
|
||||||
});
|
});
|
||||||
|
|
||||||
system.RegisterHostThread();
|
system.RegisterHostThread();
|
||||||
|
@ -2047,6 +2069,7 @@ void GMainWindow::OnStartGame() {
|
||||||
|
|
||||||
emu_thread->SetRunning(true);
|
emu_thread->SetRunning(true);
|
||||||
|
|
||||||
|
qRegisterMetaType<Core::Frontend::ControllerParameters>("Core::Frontend::ControllerParameters");
|
||||||
qRegisterMetaType<Core::Frontend::SoftwareKeyboardParameters>(
|
qRegisterMetaType<Core::Frontend::SoftwareKeyboardParameters>(
|
||||||
"Core::Frontend::SoftwareKeyboardParameters");
|
"Core::Frontend::SoftwareKeyboardParameters");
|
||||||
qRegisterMetaType<Core::System::ResultStatus>("Core::System::ResultStatus");
|
qRegisterMetaType<Core::System::ResultStatus>("Core::System::ResultStatus");
|
||||||
|
|
|
@ -37,6 +37,7 @@ enum class InstalledEntryType;
|
||||||
class GameListPlaceholder;
|
class GameListPlaceholder;
|
||||||
|
|
||||||
namespace Core::Frontend {
|
namespace Core::Frontend {
|
||||||
|
struct ControllerParameters;
|
||||||
struct SoftwareKeyboardParameters;
|
struct SoftwareKeyboardParameters;
|
||||||
} // namespace Core::Frontend
|
} // namespace Core::Frontend
|
||||||
|
|
||||||
|
@ -116,9 +117,12 @@ signals:
|
||||||
|
|
||||||
void UpdateInstallProgress();
|
void UpdateInstallProgress();
|
||||||
|
|
||||||
|
void ControllerSelectorReconfigureFinished();
|
||||||
|
|
||||||
void ErrorDisplayFinished();
|
void ErrorDisplayFinished();
|
||||||
|
|
||||||
void ProfileSelectorFinishedSelection(std::optional<Common::UUID> uuid);
|
void ProfileSelectorFinishedSelection(std::optional<Common::UUID> uuid);
|
||||||
|
|
||||||
void SoftwareKeyboardFinishedText(std::optional<std::u16string> text);
|
void SoftwareKeyboardFinishedText(std::optional<std::u16string> text);
|
||||||
void SoftwareKeyboardFinishedCheckDialog();
|
void SoftwareKeyboardFinishedCheckDialog();
|
||||||
|
|
||||||
|
@ -127,6 +131,8 @@ signals:
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void OnLoadComplete();
|
void OnLoadComplete();
|
||||||
|
void ControllerSelectorReconfigureControllers(
|
||||||
|
const Core::Frontend::ControllerParameters& parameters);
|
||||||
void ErrorDisplayDisplayError(QString body);
|
void ErrorDisplayDisplayError(QString body);
|
||||||
void ProfileSelectorSelectProfile();
|
void ProfileSelectorSelectProfile();
|
||||||
void SoftwareKeyboardGetText(const Core::Frontend::SoftwareKeyboardParameters& parameters);
|
void SoftwareKeyboardGetText(const Core::Frontend::SoftwareKeyboardParameters& parameters);
|
||||||
|
|