Files
thunderpad/src/joypadw.cpp
2025-06-30 15:46:18 -04:00

241 lines
8.6 KiB
C++

#include "joypadw.h"
JoyPadWidget::JoyPadWidget( JoyPad* jp, int i, QWidget* parent )
: QWidget(parent) {
//initialize things, build the accessible dialog
joypad = jp;
index = i;
flashcount = 0;
quickset = NULL;
// Create main vertical layout
layoutMain = new QVBoxLayout(this);
layoutMain->setSpacing(10);
layoutMain->setMargin(10);
// Create horizontal layout for axes and buttons groups
topLayout = new QHBoxLayout();
// Create axes group
axesGroup = new QGroupBox("Axes", this);
QVBoxLayout *axesLayout = new QVBoxLayout(axesGroup);
axesList = new QListWidget(axesGroup);
axesList->setAccessibleName("Axes List");
axesList->setAccessibleDescription("List of joystick axes for configuration");
axesLayout->addWidget(axesList);
btnConfigureAxis = new QPushButton("Configure Selected Axis", axesGroup);
btnConfigureAxis->setEnabled(false);
btnConfigureAxis->setAccessibleDescription("Configure the currently selected axis");
btnConfigureAxis->setFocusPolicy(Qt::TabFocus);
connect(btnConfigureAxis, SIGNAL(clicked()), this, SLOT(configureSelectedAxis()));
axesLayout->addWidget(btnConfigureAxis);
axisStatusLabel = new QLabel("Select an axis to configure", axesGroup);
axisStatusLabel->setWordWrap(true);
axesLayout->addWidget(axisStatusLabel);
// Create buttons group
buttonsGroup = new QGroupBox("Buttons", this);
QVBoxLayout *buttonsLayout = new QVBoxLayout(buttonsGroup);
buttonsList = new QListWidget(buttonsGroup);
buttonsList->setAccessibleName("Buttons List");
buttonsList->setAccessibleDescription("List of joystick buttons for configuration");
buttonsLayout->addWidget(buttonsList);
btnConfigureButton = new QPushButton("Configure Selected Button", buttonsGroup);
btnConfigureButton->setEnabled(false);
btnConfigureButton->setAccessibleDescription("Configure the currently selected button");
btnConfigureButton->setFocusPolicy(Qt::TabFocus);
connect(btnConfigureButton, SIGNAL(clicked()), this, SLOT(configureSelectedButton()));
buttonsLayout->addWidget(btnConfigureButton);
buttonStatusLabel = new QLabel("Select a button to configure", buttonsGroup);
buttonStatusLabel->setWordWrap(true);
buttonsLayout->addWidget(buttonStatusLabel);
// Add groups to horizontal layout
topLayout->addWidget(axesGroup);
topLayout->addWidget(buttonsGroup);
layoutMain->addLayout(topLayout);
// Create the underlying widgets for compatibility
foreach (Axis *axis, joypad->axes) {
AxisWidget *aw = new AxisWidget(axis, this);
aw->setVisible(false); // Hide the old widgets
axes.append(aw);
connect( aw, SIGNAL( flashed( bool ) ), this, SLOT( flash( bool )));
}
foreach (Button *button, joypad->buttons) {
ButtonWidget *bw = new ButtonWidget(button, this);
bw->setVisible(false); // Hide the old widgets
buttons.append(bw);
connect( bw, SIGNAL( flashed( bool ) ), this, SLOT( flash( bool )));
}
// Control buttons
QHBoxLayout *controlLayout = new QHBoxLayout();
btnClear = new QPushButton(QIcon::fromTheme("edit-clear"), "Clear All", this);
btnClear->setAccessibleDescription("Clear all axis and button configurations");
btnClear->setFocusPolicy(Qt::StrongFocus);
btnClear->setAccessibleName("Clear All Button");
connect(btnClear, SIGNAL(clicked()), this, SLOT(clear()));
controlLayout->addWidget(btnClear);
btnAll = new QPushButton("Quick Set", this);
btnAll->setAccessibleDescription("Quick configuration mode for all controls");
btnAll->setFocusPolicy(Qt::StrongFocus); // Try StrongFocus instead of TabFocus
btnAll->setAccessibleName("Quick Set Button");
connect(btnAll, SIGNAL(clicked()), this, SLOT(setAll()));
controlLayout->addWidget(btnAll);
controlLayout->addStretch();
layoutMain->addLayout(controlLayout);
// Connect selection change signals
connect(axesList, SIGNAL(itemSelectionChanged()), this, SLOT(onAxisSelectionChanged()));
connect(buttonsList, SIGNAL(itemSelectionChanged()), this, SLOT(onButtonSelectionChanged()));
// Set explicit tab order to ensure all widgets are accessible
setTabOrder(axesList, btnConfigureAxis);
setTabOrder(btnConfigureAxis, buttonsList);
setTabOrder(buttonsList, btnConfigureButton);
setTabOrder(btnConfigureButton, btnClear);
setTabOrder(btnClear, btnAll);
// Populate the lists
update();
}
JoyPadWidget::~JoyPadWidget() {
//so the joypad knows that we're done.
joypad->releaseWidget();
}
void JoyPadWidget::flash( bool on ) {
//true iff this entire widget was considered "flashed" before
bool wasOn = (flashcount != 0);
//adjust the count based on this new flash
flashcount += (on?1:-1);
//if we were on and should now be off, or visa versa, flash the whole widget
if (wasOn != (flashcount != 0)) {
emit flashed(index);
}
}
void JoyPadWidget::update() {
// Update underlying widgets
foreach (AxisWidget *axis, axes) {
axis->update();
}
foreach (ButtonWidget *button, buttons) {
button->update();
}
// Update accessible lists
axesList->clear();
for (int i = 0; i < axes.size(); i++) {
QString axisName = QString("Axis %1").arg(i + 1);
QString axisDesc = axes[i]->text(); // Get current configuration description
axesList->addItem(QString("%1: %2").arg(axisName, axisDesc));
}
buttonsList->clear();
for (int i = 0; i < buttons.size(); i++) {
QString buttonName = QString("Button %1").arg(i + 1);
QString buttonDesc = buttons[i]->text(); // Get current configuration description
buttonsList->addItem(QString("%1: %2").arg(buttonName, buttonDesc));
}
}
void JoyPadWidget::clear() {
joypad->toDefault();
update();
}
void JoyPadWidget::setAll() {
//quickset is NULL if there is no quickset dialog, and a pointer to the
//dialog otherwise. This is so we can forward jsevents properly.
quickset = new QuickSet(joypad, this);
quickset->exec();
update();
delete quickset;
quickset = NULL;
}
void JoyPadWidget::jsevent( const js_event& msg ) {
//notify the component this event applies to. this cannot generate anything
//other than a flash :)
unsigned int type = msg.type & ~JS_EVENT_INIT;
if (type == JS_EVENT_AXIS) {
if (msg.number < axes.size()) axes[msg.number]->jsevent(msg.value);
else debug_mesg("DEBUG: axis index out of range: %d\n", msg.value);
}
else if (type == JS_EVENT_BUTTON) {
if (msg.number < buttons.size()) buttons[msg.number]->jsevent(msg.value);
else debug_mesg("DEBUG: button index out of range: %d\n", msg.value);
}
//if we're doing quickset, it needs to know when we do something.
if (quickset != NULL) {
quickset->jsevent(msg);
}
}
void JoyPadWidget::updateButtonLayoutLists(const QStringList layoutNames) {
foreach (ButtonWidget *bw, buttons) {
bw->layoutNames = layoutNames;
}
}
void JoyPadWidget::configureSelectedAxis() {
int selectedRow = axesList->currentRow();
if (selectedRow >= 0 && selectedRow < axes.size()) {
// Use the public configure method for accessibility
axes[selectedRow]->configure();
// Update the display after configuration
update();
}
}
void JoyPadWidget::configureSelectedButton() {
int selectedRow = buttonsList->currentRow();
if (selectedRow >= 0 && selectedRow < buttons.size()) {
// Use the public configure method for accessibility
buttons[selectedRow]->configure();
// Update the display after configuration
update();
}
}
void JoyPadWidget::onAxisSelectionChanged() {
bool hasSelection = axesList->currentRow() >= 0;
btnConfigureAxis->setEnabled(hasSelection);
if (hasSelection) {
int selectedRow = axesList->currentRow();
if (selectedRow < axes.size()) {
axisStatusLabel->setText(QString("Selected: %1").arg(axesList->currentItem()->text()));
}
} else {
axisStatusLabel->setText("Select an axis to configure");
}
}
void JoyPadWidget::onButtonSelectionChanged() {
bool hasSelection = buttonsList->currentRow() >= 0;
btnConfigureButton->setEnabled(hasSelection);
if (hasSelection) {
int selectedRow = buttonsList->currentRow();
if (selectedRow < buttons.size()) {
buttonStatusLabel->setText(QString("Selected: %1").arg(buttonsList->currentItem()->text()));
}
} else {
buttonStatusLabel->setText("Select a button to configure");
}
}