o cleanup

This commit is contained in:
optixx
2009-04-22 20:04:28 +02:00
parent 55e3468f74
commit 0c378a9f7c
1078 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,180 @@
void CodeEditorWindow::setup() {
window = new QWidget;
window->setObjectName("code-editor-window");
layout = new QVBoxLayout;
layout->setMargin(Style::WindowMargin);
layout->setSpacing(0);
descLabel = new QLabel("Description:");
layout->addWidget(descLabel);
description = new QTextEdit;
layout->addWidget(description);
layout->addSpacing(Style::WidgetSpacing);
codeLabel = new QLabel("Cheat code(s):");
layout->addWidget(codeLabel);
codeLayout = new QHBoxLayout; {
codeLayout->setMargin(0);
codeList = new QListWidget;
codeLayout->addWidget(codeList);
codeLayout->addSpacing(Style::WidgetSpacing);
controls = new QVBoxLayout; {
controls->setMargin(0);
codeValue = new QLineEdit;
controls->addWidget(codeValue);
codeAdd = new QPushButton("Add Code");
controls->addWidget(codeAdd);
codeDelete = new QPushButton("Delete Code");
controls->addWidget(codeDelete);
codeDeleteAll = new QPushButton("Delete All");
controls->addWidget(codeDeleteAll);
spacer = new QWidget;
spacer->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
controls->addWidget(spacer);
}
codeLayout->addLayout(controls);
}
layout->addLayout(codeLayout);
layout->addSpacing(Style::WidgetSpacing);
enabled = new QCheckBox("Enable this cheat code");
layout->addWidget(enabled);
finishControls = new QHBoxLayout; {
okButton = new QPushButton("Ok");
finishControls->addWidget(okButton);
cancelButton = new QPushButton("Cancel");
finishControls->addWidget(cancelButton);
}
finishControls->setSpacing(Style::WidgetSpacing);
layout->addLayout(finishControls);
window->setLayout(layout);
window->setMinimumSize(400, 375);
connect(codeList, SIGNAL(itemSelectionChanged()), this, SLOT(listChanged()));
connect(codeValue, SIGNAL(textChanged(const QString&)), this, SLOT(codeChanged()));
connect(codeAdd, SIGNAL(released()), this, SLOT(addCodeToList()));
connect(codeDelete, SIGNAL(released()), this, SLOT(deleteCodeFromList()));
connect(codeDeleteAll, SIGNAL(released()), this, SLOT(deleteAllCodesFromList()));
connect(okButton, SIGNAL(released()), this, SLOT(accept()));
connect(cancelButton, SIGNAL(released()), this, SLOT(dismiss()));
}
void CodeEditorWindow::syncUi() {
//only activate add button when code is valid
string code = codeValue->text().toUtf8().data();
Cheat::cheat_t temp;
bool valid = cheat.decode(code, temp);
codeAdd->setEnabled(valid);
//only activate delete button when a code is selected
QListWidgetItem *item = codeList->currentItem();
codeDelete->setEnabled(item && item->isSelected());
//only activate delete all / ok buttons when there are one or more codes entered
codeDeleteAll->setEnabled(codeList->count() > 0);
okButton->setEnabled(codeList->count() > 0);
}
void CodeEditorWindow::listChanged() { syncUi(); }
void CodeEditorWindow::codeChanged() { syncUi(); }
void CodeEditorWindow::addCodeToList() {
string code = codeValue->text().toUtf8().data();
Cheat::cheat_t temp;
if(cheat.decode(code, temp) == true) codeList->addItem(utf8() << code);
syncUi();
}
void CodeEditorWindow::deleteCodeFromList() {
int index = codeList->currentRow();
if(index >= 0) {
QListWidgetItem *item = codeList->takeItem(index);
delete item;
}
syncUi();
}
void CodeEditorWindow::deleteAllCodesFromList() {
codeList->clear();
syncUi();
}
void CodeEditorWindow::accept() {
string desc = description->toPlainText().toUtf8().data();
string code;
for(unsigned i = 0; i < codeList->count(); i++) {
code << (codeList->item(i)->text().toUtf8().data());
if(i != codeList->count() - 1) code << "+";
}
if(activeCode == -1) {
//adding a new code
cheat.add(enabled->isChecked(), code, desc);
winCheatEditor->reloadList();
} else if(codeList->count() > 0) {
//editing an existing code
cheat.edit(activeCode, enabled->isChecked(), code, desc);
winCheatEditor->updateList();
} else {
//deleting an existing code
cheat.remove(activeCode);
winCheatEditor->reloadList();
}
dismiss();
}
void CodeEditorWindow::dismiss() {
activeCode = -1;
window->hide();
}
void CodeEditorWindow::addCode() {
activeCode = -1;
description->setPlainText("");
codeList->clear();
codeValue->setText("");
enabled->setCheckState(Qt::Unchecked);
showWindow("Add New Cheat Code");
}
void CodeEditorWindow::editCode(unsigned code) {
activeCode = code;
codeList->clear();
codeValue->setText("");
Cheat::cheat_t item;
cheat.get(activeCode, item);
description->setPlainText(utf8() << item.desc);
lstring part;
part.split("+", item.code);
for(unsigned i = 0; i < item.count; i++) codeList->addItem(utf8() << part[i]);
enabled->setCheckState(item.enabled ? Qt::Checked : Qt::Unchecked);
showWindow("Edit Existing Cheat Code");
}
void CodeEditorWindow::showWindow(const char *title) {
syncUi();
window->setWindowTitle(title);
utility.showCentered(window);
}
CodeEditorWindow::CodeEditorWindow() {
activeCode = -1;
}

View File

@@ -0,0 +1,43 @@
class CodeEditorWindow : public QObject {
Q_OBJECT
public:
QWidget *window;
QVBoxLayout *layout;
QLabel *descLabel;
QTextEdit *description;
QLabel *codeLabel;
QHBoxLayout *codeLayout;
QListWidget *codeList;
QVBoxLayout *controls;
QLineEdit *codeValue;
QPushButton *codeAdd;
QPushButton *codeDelete;
QPushButton *codeDeleteAll;
QWidget *spacer;
QCheckBox *enabled;
QHBoxLayout *finishControls;
QPushButton *okButton;
QPushButton *cancelButton;
void setup();
void syncUi();
void addCode();
void editCode(unsigned code);
CodeEditorWindow();
public slots:
void listChanged();
void codeChanged();
void addCodeToList();
void deleteCodeFromList();
void deleteAllCodesFromList();
void accept();
void dismiss();
private:
signed activeCode;
void showWindow(const char *title);
friend class CheatEditorWindow;
} *winCodeEditor;

View File

@@ -0,0 +1,454 @@
void InputCaptureWindow::setup() {
window = new Window;
window->setObjectName("input-capture-window");
window->setWindowTitle("Input Capture");
layout = new QVBoxLayout;
layout->setMargin(Style::WindowMargin);
layout->setSpacing(0);
hlayout = new QHBoxLayout;
hlayout->setSpacing(Style::WidgetSpacing); {
title = new QLabel;
hlayout->addWidget(title, 0, Qt::AlignTop);
mouseAxes = new QPushButton(" Assign Mouse Axis ");
mouseAxes->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
hlayout->addWidget(mouseAxes, 0, Qt::AlignTop);
mouseButtons = new QPushButton(" Assign Mouse Button ");
mouseButtons->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
hlayout->addWidget(mouseButtons, 0, Qt::AlignTop);
}
layout->addLayout(hlayout);
imageSpacer = new QWidget;
imageSpacer->setFixedSize(Style::WidgetSpacing, Style::WidgetSpacing);
layout->addWidget(imageSpacer);
imageWidget = new ImageWidget;
layout->addWidget(imageWidget, 0, Qt::AlignHCenter);
spacer = new QWidget;
spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
layout->addWidget(spacer);
window->setLayout(layout);
connect(mouseAxes, SIGNAL(released()), this, SLOT(assignMouseAxis()));
connect(mouseButtons, SIGNAL(released()), this, SLOT(assignMouseButton()));
winInputMouseCaptureWindow = new InputMouseCaptureWindow;
winInputMouseCaptureWindow->setup();
winInputCalibration = new InputCalibrationWindow;
winInputCalibration->setup();
}
void InputCaptureWindow::activate(InputObject *object) {
if(!activeGroup) window->hide();
utf8 info;
info << "<b>ID:</b> ";
if(object->parent) {
InputDevice *device = dynamic_cast<InputDevice*>(object->parent);
if(device) info << "Controller port " << (int)(device->port + 1) << " <b>::</b> ";
else info << "User interface <b>::</b> ";
info << object->parent->name << " <b>::</b> ";
}
info << object->name << "<br>";
activeObject = object;
if(activeObject->type == InputObject::Button) {
mouseAxes->hide();
mouseButtons->show();
info << "Press any key or button to assign to this ID.";
} else /*(activeObject->type == InputObject::Axis)*/ {
mouseAxes->show();
mouseButtons->hide();
info << "Move any axis to assign to this ID.";
}
if(dynamic_cast<Joypad*>(activeObject->parent)) {
imageSpacer->show();
imageWidget->setFixedSize(480, 210);
imageWidget->show();
} else {
imageSpacer->hide();
imageWidget->hide();
}
title->setText(info);
utility.showCentered(window);
}
void InputCaptureWindow::activate(InputGroup *group) {
activeGroup = group;
groupIndex = 0;
window->hide();
activate((*activeGroup)[groupIndex]);
}
void InputCaptureWindow::inputEvent(uint16_t code, bool forceAssign /* = false */) {
if(!activeObject || inputLock == true) return;
//input polling is global, need to block mouse actions that may be UI interactions.
//custom controls on window allow mouse assignment instead.
if(forceAssign == false) {
if(winInputMouseCaptureWindow->window->isActiveWindow()) {
winInputMouseCaptureWindow->inputEvent(code);
return;
}
if(!window->isActiveWindow()) return;
//get as much info as possible about this code
InputCode::type_t type = InputCode::type(code);
InputCode::axistype_t axisType = InputCode::axisType(code);
int joypadNumber = InputCode::joypadNumber(code);
int16_t state = inputManager.state(code);
unsigned distance = abs(state - inputManager.lastState(code));
if(type == InputCode::JoypadHat) {
//hats can be in any of nine clock-wise states (4x direct, 4x angled and centered.)
//only map when hat is moved to an explicit direction.
if(state != joypad<>::hat_up && state != joypad<>::hat_down
&& state != joypad<>::hat_left && state != joypad<>::hat_right) return;
}
if(type == InputCode::JoypadAxis) {
//require a degree of resistance to prevent accidental mapping
if(axisType == InputCode::Stick) {
//require axis to be pressed almost completely toward a specific direction
if(state > -28672 && state < +28672) return;
} else if(axisType == InputCode::Trigger) {
//require trigger to be at least 75% pressed down
if(state > -16384) return;
} else {
//invalid axis type: most likely the controller has yet to be calibrated
if(joypadNumber < 0) return; //should never occur
//some analog triggers report phantom motion even when user does not touch gamepad
if(distance < 64) return; //require some degree of force to trigger calibration
if(state > -8192 && state < +8192) return; //ignore center motion
if(inputManager.calibrated(joypadNumber) == false) {
winInputCalibration->activate(joypadNumber);
}
//block assignment until controller is fully calibrated
return;
}
}
if(activeObject->type == InputObject::Axis) {
if(type == InputCode::KeyboardButton
|| type == InputCode::MouseAxis
|| type == InputCode::MouseButton
|| type == InputCode::JoypadHat
|| type == InputCode::JoypadButton
) return;
//uni-directional trigger cannot map to bi-directional axis
if(type == InputCode::JoypadAxis && axisType == InputCode::Trigger) return;
}
if(activeObject->type == InputObject::Button) {
if(type == InputCode::MouseAxis
|| type == InputCode::MouseButton
) return;
//only capture on button press, not release
if(type != InputCode::JoypadAxis && state == false) return;
}
//if assigning a complete controller set, ensure requested key has not been assigned
//to a previous entry in the group already. this prevents slow motion of joypad axes
//from assigning the same value to multiple entries in rapid succession.
if(activeGroup && groupIndex > 0) {
for(unsigned i = 0; i < groupIndex; i++) {
if(code == (*activeGroup)[i]->code) {
//joypad hats and axes have multiple states, and are differentiated by modifier.
//allow mapping only if requested modifier is unique.
if(type == InputCode::JoypadHat) {
if(state == joypad<>::hat_up && (*activeGroup)[i]->modifier == InputObject::Up ) return;
if(state == joypad<>::hat_down && (*activeGroup)[i]->modifier == InputObject::Down ) return;
if(state == joypad<>::hat_left && (*activeGroup)[i]->modifier == InputObject::Left ) return;
if(state == joypad<>::hat_right && (*activeGroup)[i]->modifier == InputObject::Right) return;
} else if(type == InputCode::JoypadAxis) {
if(axisType == InputCode::Stick) {
if(state < 0 && (*activeGroup)[i]->modifier == InputObject::Lo) return;
if(state >= 0 && (*activeGroup)[i]->modifier == InputObject::Hi) return;
} else if(axisType == InputCode::Trigger) {
if((*activeGroup)[i]->modifier == InputObject::Trigger) return;
}
} else {
//this code has already been used, do not map it
return;
}
}
}
}
}
//bind code and update GUI input assignment list
activeObject->bind(code);
winInputSettings->updateList();
activeObject = 0;
//ignore multiple simultaneous state changes.
//this helps with joypads that only activate
//analog inputs after the first button press.
inputLock = true;
for(unsigned i = 0; i < 2; i++) inputManager.refresh();
inputLock = false;
if(!activeGroup) {
window->hide();
winInputMouseCaptureWindow->window->hide();
} else {
//try and map the next code in this input group
groupIndex++;
if(groupIndex < activeGroup->size()) {
activate((*activeGroup)[groupIndex]);
} else {
//all group codes mapped
window->hide();
winInputMouseCaptureWindow->window->hide();
activeGroup = 0;
}
}
}
void InputCaptureWindow::assignMouseAxis() {
//refresh input state so that mouse release event (from SIGNAL(released())
//is not sent immediately after window is visible.
inputManager.refresh();
winInputMouseCaptureWindow->activate(InputMouseCaptureWindow::AxisMode);
}
void InputCaptureWindow::assignMouseButton() {
inputManager.refresh();
winInputMouseCaptureWindow->activate(InputMouseCaptureWindow::ButtonMode);
}
InputCaptureWindow::InputCaptureWindow() {
activeObject = 0;
activeGroup = 0;
groupIndex = 0;
inputLock = false;
}
void InputCaptureWindow::Window::closeEvent(QCloseEvent*) {
//window closed by user, cancel key assignment
winInputCapture->activeObject = 0;
winInputCapture->activeGroup = 0;
}
void InputCaptureWindow::ImageWidget::paintEvent(QPaintEvent*) {
//currently, there is only an image available for the joypad.
//in the future, this routine should determine which type of
//image to draw via activeObject->parent's derived class type.
QPainter painter(this);
QPixmap pixmap(":/joypad.png");
painter.drawPixmap(0, 0, pixmap);
}
//=======================
//InputMouseCaptureWindow
//=======================
void InputMouseCaptureWindow::setup() {
window = new QWidget;
window->setObjectName("input-mouse-capture-window");
window->setWindowTitle("Mouse Input Capture");
layout = new QVBoxLayout;
layout->setMargin(Style::WindowMargin);
layout->setSpacing(0);
info = new QLabel;
layout->addWidget(info);
layout->addSpacing(Style::WidgetSpacing);
captureBox = new QLabel("[ capture box ]");
captureBox->setObjectName("mouse-capture-box");
captureBox->setAlignment(Qt::AlignCenter);
captureBox->setFixedHeight(120);
layout->addWidget(captureBox);
buttonLayout = new QHBoxLayout;
buttonLayout->setSpacing(Style::WidgetSpacing); {
xAxis = new QPushButton("X-axis");
buttonLayout->addWidget(xAxis);
yAxis = new QPushButton("Y-axis");
buttonLayout->addWidget(yAxis);
}
layout->addLayout(buttonLayout);
spacer = new QWidget;
spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
layout->addWidget(spacer);
window->setLayout(layout);
connect(xAxis, SIGNAL(released()), this, SLOT(assignAxisX()));
connect(yAxis, SIGNAL(released()), this, SLOT(assignAxisY()));
}
void InputMouseCaptureWindow::activate(InputMouseCaptureWindow::Mode mode_) {
window->hide();
activeMode = mode_;
if(activeMode == AxisMode) {
captureBox->hide();
xAxis->show();
yAxis->show();
info->setText(utf8()
<< "To assign a mouse axis to this ID, please click the desired axis button below,<br>"
<< "using the mouse that you want the axis to be assigned to."
);
activeMouse = -1;
} else /*(activeMode == ButtonMode) */ {
captureBox->show();
xAxis->hide();
yAxis->hide();
info->setText(utf8()
<< "To assign a mouse button to this ID, please place the mouse you wish to map<br>"
<< "over the capture box below, and then click any mouse button to set assignment."
);
}
utility.showCentered(window);
}
//this is only called when isActiveWindow() == true
void InputMouseCaptureWindow::inputEvent(uint16_t code) {
InputCode::type_t type = InputCode::type(code);
int16_t state = inputManager.state(code);
if(activeMode == AxisMode) {
//when pressing down mouse button (eg to select "X-axis" or "Y-axis"),
//record mouse index for later assignment
if(type == InputCode::MouseButton && state == true) {
activeMouse = InputCode::mouseNumber(code);
return;
}
} else if(activeMode == ButtonMode) {
//if this is a mouse button that is being released ...
if(type == InputCode::MouseButton && state == false) {
//ensure button was clicked inside active capture box
QRect windowRect = window->geometry();
QRect widgetRect = captureBox->geometry();
unsigned wx = windowRect.left() + widgetRect.left();
unsigned wy = windowRect.top() + widgetRect.top();
unsigned px = QCursor::pos().x();
unsigned py = QCursor::pos().y();
if(px < wx || px >= wx + widgetRect.size().width() ) return;
if(py < wy || py >= wy + widgetRect.size().height()) return;
winInputCapture->inputEvent(code, true);
return;
}
}
}
void InputMouseCaptureWindow::assignAxisX() {
if(activeMouse >= 0) {
winInputCapture->inputEvent(mouse<>::index(activeMouse, mouse<>::x), true);
}
}
void InputMouseCaptureWindow::assignAxisY() {
if(activeMouse >= 0) {
winInputCapture->inputEvent(mouse<>::index(activeMouse, mouse<>::y), true);
}
}
//====================
//InputCalibrateWindow
//====================
//background:
//===========
//HID devices work by sending device state *changes* only. what this means is that when an application is started,
//it does not know the current state of said device. the keyboard and mouse are exceptions, as the OS globally
//tracks their states. but this does apply to joypads. once a button is pressed, or an axis is moved, the entire
//joypad state will be sent in a message, that APIs such as DirectInput and SDL will buffer.
//
//to complicate matters, recent joypads have added pressure-sensitive buttons (triggers), in addition to the
//existing analog sticks. but this functionality was not extended to the USB HID state or to various platform
//input APIs. instead, they are treated exactly like axes.
//
//however, an application needs to treat these two input types distinctly:
//a stick is a bi-directional input. the stick starts off centered, and can be moved left or right, or up or down.
//a trigger is a uni-directional input. it can only be pushed down.
//
//a stick's default, unpressed state is centered (0), whereas a trigger's default state is fully depressed (+32767.)
//but because the default state is not available until the user presses a button on a joypad, it is not possible to
//calibrate a joypad on startup. all axes will report a value of 0, even if buttons are depressed.
//
//thusly, this class is needed. it will spawn a window upon the first attempt to map a joypad axis after startup.
//by the point this window appears, an axis must have been moved, so the joypad state is now valid. but since it's
//not possible to tell which button was pressed or which axis was moved, it's possible the axis that we're trying to
//map was moved. so querying its state now might result in improper mapping. so instead, this window is shown, and
//the user is asked not to press any buttons or move any axes. after hitting okay to confirm the joypad is idle,
//the joypad can finally be calibrated properly.
//
//upon assignment, the calibration data is appended to the input assignment value (eg "joypad00.axis00::trigger"),
//so that calibration is not necessary every time the emulator is run -- only when modifying input mapping on an axis.
void InputCalibrationWindow::activate(unsigned joy) {
//do not override an already active calibration window
if(window->isVisible()) return;
activeJoypad = joy;
info->setText(utf8()
<< "Joypad #" << joy << " needs to be calibrated before it can be mapped. "
<< "Please ensure that<br>no buttons are pressed, "
<< "and all axes are centered before pressing okay."
);
utility.showCentered(window);
ok->setFocus();
}
void InputCalibrationWindow::setup() {
window = new Window;
window->setObjectName("input-calibrate-window");
window->setWindowTitle("Joypad Calibration");
layout = new QVBoxLayout;
layout->setMargin(Style::WindowMargin);
layout->setSpacing(0);
info = new QLabel;
layout->addWidget(info);
layout->addSpacing(Style::WidgetSpacing);
ok = new QPushButton("Ok");
layout->addWidget(ok);
spacer = new QWidget;
spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
layout->addWidget(spacer);
window->setLayout(layout);
connect(ok, SIGNAL(released()), this, SLOT(dismiss()));
}
void InputCalibrationWindow::dismiss() {
window->hide();
if(activeJoypad != -1) {
inputManager.calibrate(activeJoypad);
activeJoypad = -1;
}
}
void InputCalibrationWindow::Window::closeEvent(QCloseEvent*) {
winInputCalibration->dismiss();
}

View File

@@ -0,0 +1,88 @@
class InputCaptureWindow : public QObject {
Q_OBJECT
public:
struct Window : public QWidget {
void closeEvent(QCloseEvent*);
} *window;
QVBoxLayout *layout;
QHBoxLayout *hlayout;
QLabel *title;
QPushButton *mouseAxes;
QPushButton *mouseButtons;
QWidget *imageSpacer;
struct ImageWidget : public QWidget {
void paintEvent(QPaintEvent*);
} *imageWidget;
QWidget *spacer;
void setup();
void activate(InputObject *object);
void activate(InputGroup *group);
void inputEvent(uint16_t code, bool forceAssign = false);
InputCaptureWindow();
public slots:
void assignMouseAxis();
void assignMouseButton();
private:
InputObject *activeObject;
InputGroup *activeGroup;
unsigned groupIndex;
bool inputLock;
friend class InputCaptureWindow::Window;
} *winInputCapture;
class InputMouseCaptureWindow : public QObject {
Q_OBJECT
public:
enum Mode { AxisMode, ButtonMode };
QWidget *window;
QVBoxLayout *layout;
QLabel *info;
QLabel *captureBox;
QHBoxLayout *buttonLayout;
QPushButton *xAxis;
QPushButton *yAxis;
QWidget *spacer;
void setup();
void activate(Mode);
void inputEvent(uint16_t code);
public slots:
void assignAxisX();
void assignAxisY();
private:
Mode activeMode;
signed activeMouse;
} *winInputMouseCaptureWindow;
class InputCalibrationWindow : public QObject {
Q_OBJECT
public:
struct Window : public QWidget {
void closeEvent(QCloseEvent*);
} *window;
QVBoxLayout *layout;
QLabel *info;
QPushButton *ok;
QWidget *spacer;
void setup();
void activate(unsigned joy);
public slots:
void dismiss();
private:
int activeJoypad;
friend class InputCalibrationWindow::Window;
} *winInputCalibration;