0,0 → 1,401 |
#include "MacroWidget.h" |
|
MacroWidget::MacroWidget(QWidget *parent) : QWidget(parent) |
{ |
sigmapTransmit = new QSignalMapper(); |
sigmapKeybind = new QSignalMapper(); |
|
btnExport = new QPushButton("&Export"); |
btnImport = new QPushButton("&Import"); |
btnAddMacro = new QPushButton("&Add"); |
btnRemoveMacro = new QPushButton("&Remove"); |
btnClear = new QPushButton("&Clear"); |
currKeyBindInfo = QPair<QPushButton*,int>(NULL, 0); |
|
mainLayout = new QGridLayout(); |
|
macroCount = 0; |
connected = false; |
lastKnownFilePath = "."; |
|
ioLayout = new QHBoxLayout(); |
ioLayout->addWidget(btnAddMacro); |
ioLayout->addWidget(btnRemoveMacro); |
ioLayout->addWidget(btnClear); |
ioLayout->addWidget(btnExport); |
ioLayout->addWidget(btnImport); |
ioLayout->addStretch(); |
mainLayout->addLayout(ioLayout, 0, 0, 1, 2); |
|
for (int i = 0; i < MACRO_DEFAULT_COUNT; i++) { |
Macro_AddEntry(); |
} |
|
setLayout(mainLayout); |
|
connect(btnAddMacro, SIGNAL(clicked()), this, SLOT(Macro_AddEntry())); |
connect(btnRemoveMacro, SIGNAL(clicked()), this, SLOT(Macro_RemoveEntry())); |
connect(btnClear, SIGNAL(clicked()), this, SLOT(Macro_Clear())); |
connect(btnExport, SIGNAL(clicked()), this, SLOT(Macro_WriteToFile())); |
connect(btnImport, SIGNAL(clicked()), this, SLOT(Macro_ReadFromFile())); |
connect(sigmapTransmit, SIGNAL(mapped(QWidget*)), this, SLOT(Macro_InitTransmit(QWidget*))); |
connect(sigmapKeybind, SIGNAL(mapped(int)), this, SLOT(Macro_KeybindPrompt(int))); |
|
// Register global event process for keyboard shortcut handling |
qApp->installEventFilter(this); |
} |
|
MacroWidget::~MacroWidget() |
{ |
|
} |
|
QSize MacroWidget::sizeHint() const |
{ |
return this->minimumSizeHint(); |
} |
|
void MacroWidget::Macro_EnableTransmit() |
{ |
connected = true; |
for (int i = 0; i < macroBtnSendList.size(); i++) { |
macroBtnSendList[i]->setEnabled(true); |
} |
} |
|
void MacroWidget::Macro_DisableTransmit() |
{ |
connected = false; |
for (int i = 0; i < macroBtnSendList.size(); i++) { |
macroBtnSendList[i]->setEnabled(false); |
} |
} |
|
void MacroWidget::Macro_InitTransmit(QWidget *t) |
{ |
if (connected) { |
QTextEdit *text = qobject_cast<QTextEdit*>(t); |
emit Macro_TransmitText(text->toPlainText().toUtf8()); |
} |
} |
|
void MacroWidget::Macro_KeybindPrompt(int id) |
{ |
QPushButton *btn = qobject_cast<QPushButton*>(sigmapKeybind->mapping(id)); |
|
// Check to make sure we arn't processing another key first |
if (currKeyBindInfo.first != NULL) { |
currKeyBindInfo.first->setText("Hotkey: None"); |
currKeyBindInfo.first->setDown(false); |
currKeyBindInfo.first->removeEventFilter(this); |
} |
|
// Mark and save button as waiting for key sequence |
btn->setDown(true); |
btn->setText("Waiting for Key.."); |
currKeyBindInfo = QPair<QPushButton*,int>(btn, id); |
|
// Remove current keybinding for this macro |
int index = registeredKeyMacroIDs.indexOf(id); |
if (index >= 0) { |
registeredKeySequences.removeAt(index); |
registeredKeyMacroIDs.removeAt(index); |
} |
|
// Inspect all following keyboard events |
btn->installEventFilter(this); |
} |
|
void MacroWidget::Macro_AddEntry() |
{ |
macroCount++; |
|
// Create new layout/widgets |
QLineEdit *lineEdit = new QLineEdit(QString("Macro %1").arg(macroCount)); |
lineEdit->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); |
lineEdit->setMinimumWidth(100); |
lineEdit->setAlignment(Qt::AlignCenter); |
macroNameList.append(lineEdit); |
|
QTextEdit *textEdit = new QTextEdit(); |
textEdit->setMinimumHeight(50); |
textEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); |
textEdit->setWordWrapMode(QTextOption::NoWrap); |
textEdit->setFont(QFont("Consolas", 8)); |
textEdit->setAcceptRichText(false); |
textEdit->setTabChangesFocus(true); |
macroValueList.append(textEdit); |
|
QPushButton *keyButton = new QPushButton("Hotkey: None"); |
keyButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); |
macroBtnKeyList.append(keyButton); |
|
QPushButton *pushButton = new QPushButton("Send Macro"); |
pushButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); |
pushButton->setEnabled(connected); |
macroBtnSendList.append(pushButton); |
|
QVBoxLayout *tmpLayout = new QVBoxLayout(); |
tmpLayout->addWidget(lineEdit); |
tmpLayout->addWidget(keyButton); |
tmpLayout->addWidget(pushButton); |
|
// Add layout/widgets to main layout |
mainLayout->addLayout(tmpLayout, macroCount, 0); |
mainLayout->addWidget(textEdit, macroCount, 1); |
mainLayout->setColumnStretch(1, 1); |
|
// Associate KeyButton with its corresponding ID |
sigmapKeybind->setMapping(keyButton, macroCount-1); |
connect(keyButton, SIGNAL(clicked()), sigmapKeybind, SLOT(map())); |
|
// Associate PushButton with its corresponding TextEdit |
sigmapTransmit->setMapping(pushButton, textEdit); |
connect(pushButton, SIGNAL(clicked()), sigmapTransmit, SLOT(map())); |
|
QLayoutItem *item = mainLayout->itemAtPosition(1, 1); |
int height = item->widget()->height() + mainLayout->verticalSpacing(); |
|
QDockWidget *parent = qobject_cast<QDockWidget*>(this->parent()); |
if (parent->isFloating()) |
parent->resize(parent->width(), parent->height() + height); |
|
btnRemoveMacro->setEnabled(true); |
} |
|
void MacroWidget::Macro_RemoveEntry() |
{ |
|
// Remove and delete layout/widgets at last macro slot |
QLayoutItem *item = mainLayout->itemAtPosition(macroCount, 0); |
while(!item->isEmpty()) |
delete item->layout()->takeAt(0)->widget(); |
delete item; |
|
item = mainLayout->itemAtPosition(macroCount, 1); |
delete item->widget(); |
|
item = mainLayout->itemAtPosition(1, 1); |
int height = item->widget()->height() + mainLayout->verticalSpacing(); |
|
// Unmap and remove widgets from lists |
QPushButton *pushButton = macroBtnSendList.back(); |
sigmapTransmit->removeMappings(pushButton); |
|
QPushButton *keyButton = macroBtnKeyList.back(); |
sigmapKeybind->removeMappings(keyButton); |
|
macroNameList.pop_back(); |
macroValueList.pop_back(); |
macroBtnSendList.pop_back(); |
macroBtnKeyList.pop_back(); |
|
int index = registeredKeyMacroIDs.indexOf(macroCount-1); |
if (index >= 0) { |
registeredKeySequences.removeAt(index); |
registeredKeyMacroIDs.removeAt(index); |
} |
|
macroCount--; |
|
QDockWidget *parent = qobject_cast<QDockWidget*>(this->parent()); |
if (parent->isFloating()) |
parent->resize(parent->width(), parent->height() - height); |
|
if (macroCount == 1) |
btnRemoveMacro->setEnabled(false); |
} |
|
void MacroWidget::Macro_Clear() |
{ |
for (int i = 0; i < macroCount; i++) { |
macroNameList[i]->setText(QString("Macro %1").arg(i+1)); |
macroValueList[i]->clear(); |
macroBtnKeyList[i]->setText("Hotkey: None"); |
} |
registeredKeyMacroIDs.clear(); |
registeredKeySequences.clear(); |
} |
|
void MacroWidget::Macro_WriteToFile() |
{ |
QString file = QFileDialog::getSaveFileName(this, "Settings XML File", lastKnownFilePath, "XML File (*.xml)"); |
QCoreApplication::processEvents(); // Wait for dialog to close |
|
if (file.size() == 0) return; |
|
// If file was selected, save directory for next time |
QFileInfo fileInfo = QFileInfo(file); |
lastKnownFilePath = fileInfo.absolutePath(); |
|
if (file.size() != 0) |
QFile::remove(file); |
|
QFile inputFile(file); |
if (!inputFile.open(QIODevice::ReadWrite | QIODevice::Text)) return; |
|
QXmlStreamWriter stream(&inputFile); |
stream.setAutoFormatting(true); |
|
stream.writeStartDocument(); |
stream.writeStartElement("Settings"); |
stream.writeStartElement("Macro"); |
|
for (int i = 0; i < macroCount; i++) { |
stream.writeStartElement("Macro_Entry"); |
|
stream.writeAttribute("Name", macroNameList[i]->text()); |
stream.writeTextElement("Value", macroValueList[i]->toPlainText()); |
|
int index = registeredKeyMacroIDs.indexOf(i); |
if (index >= 0) { |
stream.writeTextElement("Keybinding", registeredKeySequences[index].toString()); |
} else { |
stream.writeTextElement("Keybinding", ""); |
} |
|
stream.writeEndElement(); // Macro Entry |
} |
|
stream.writeEndElement(); // Macro |
stream.writeEndElement(); // Settings |
stream.writeEndDocument(); |
|
inputFile.close(); |
} |
|
void MacroWidget::Macro_ReadFromFile() |
{ |
int counter = 0; |
|
QString file = QFileDialog::getOpenFileName(this, "Settings XML File", lastKnownFilePath, "XML File (*.xml)"); |
QCoreApplication::processEvents(); // Wait for dialog to close |
|
if (file.size() == 0) return; |
|
Macro_Clear(); |
|
// If file was selected, save directory for next time |
QFileInfo fileInfo = QFileInfo(file); |
lastKnownFilePath = fileInfo.absolutePath(); |
|
QFile inputFile(file); |
if (!inputFile.open(QIODevice::ReadWrite | QIODevice::Text)) return; |
|
QXmlStreamReader stream(&inputFile); |
|
// Parse the XML file till we reach the end (or errors) |
while (!stream.atEnd() && !stream.hasError()) { |
QXmlStreamReader::TokenType token = stream.readNext(); |
|
// Ignore StartDocument |
if (token == QXmlStreamReader::StartDocument) continue; |
|
// Parse StartElements |
if (token == QXmlStreamReader::StartElement) { |
|
// Ignore elements <Settings> and <Macro> |
if (stream.name() == "Settings") continue; |
if (stream.name() == "Macro") continue; |
|
// Parse element <Macro_Entry> |
if (stream.name() == "Macro_Entry") { |
QString name, value, keybinding; |
|
// Read and save attribute value |
QXmlStreamAttributes attr = stream.attributes(); |
if (attr.hasAttribute("Name")) |
name = attr.value("Name").toString(); |
|
stream.readNext(); |
|
// Loop in this element to find all sub-elements |
while (!(stream.tokenType() == QXmlStreamReader::EndElement && stream.name() == "Macro_Entry")) { |
|
// Parse and save element value |
if (stream.tokenType() == QXmlStreamReader::StartElement) { |
if (stream.name() == "Value") { |
stream.readNext(); |
value = stream.text().toString(); |
} |
if (stream.name() == "Keybinding") { |
stream.readNext(); |
keybinding = stream.text().toString(); |
} |
} |
stream.readNext(); |
} |
|
// Write values to GUI |
if (counter == macroCount) |
Macro_AddEntry(); |
|
macroNameList[counter]->setText(name); |
macroValueList[counter]->setText(value); |
if (keybinding != "") { |
registeredKeySequences.append(QKeySequence(keybinding)); |
registeredKeyMacroIDs.append(counter); |
macroBtnKeyList[counter]->setText("Hotkey: " + keybinding); |
} |
counter++; |
} |
} |
} |
} |
|
bool MacroWidget::eventFilter(QObject *obj, QEvent *event) |
{ |
// Only process keyboard events |
if (event->type() == QEvent::KeyPress) { |
QKeyEvent *keyevent = static_cast<QKeyEvent*>(event); |
QKeySequence seq = keyevent->modifiers() + keyevent->key(); |
if ((keyevent->key() >= 0x21 && keyevent->key() <= 0x2F) || |
(keyevent->key() >= 0x3A && keyevent->key() <= 0x40) || |
(keyevent->key() >= 0x5E && keyevent->key() <= 0x7E) ) { |
seq = keyevent->key(); |
} |
|
if (connected) { |
// First check if key sequence matches any saved ones |
if (!registeredKeySequences.isEmpty()) { |
int index = registeredKeySequences.indexOf(seq); |
if (index >= 0) { |
Macro_InitTransmit(macroValueList[registeredKeyMacroIDs[index]]); |
return true; |
} |
} |
} |
|
// Then save key sequence if needed |
if (currKeyBindInfo.first != NULL) { |
// Ignore modifier keys and locks |
if (keyevent->key() == Qt::Key_Shift || keyevent->key() == Qt::Key_Control || |
keyevent->key() == Qt::Key_Meta || keyevent->key() == Qt::Key_Alt || |
keyevent->key() == Qt::Key_AltGr || keyevent->key() == Qt::Key_CapsLock || |
keyevent->key() == Qt::Key_NumLock || keyevent->key() == Qt::Key_ScrollLock) |
return true; |
|
// Reset on ESC key |
if (keyevent->key() == Qt::Key_Escape) { |
currKeyBindInfo.first->setText("Hotkey: None"); |
currKeyBindInfo.first->setDown(false); |
currKeyBindInfo.first->removeEventFilter(this); |
currKeyBindInfo = QPair<QPushButton*, int>(NULL, 0); |
return true; |
} |
|
// Otherwise save key sequence if it doesnt already exist |
if (!registeredKeySequences.contains(seq)) { |
registeredKeySequences.append(seq); |
registeredKeyMacroIDs.append(currKeyBindInfo.second); |
currKeyBindInfo.first->setText("Hotkey: " + seq.toString()); |
currKeyBindInfo.first->setDown(false); |
currKeyBindInfo.first->removeEventFilter(this); |
currKeyBindInfo = QPair<QPushButton*, int>(NULL, 0); |
return true; |
} |
} |
} |
|
return QWidget::eventFilter(obj, event); |
} |