Blame | Last modification | View Log | Download | RSS feed
#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 handlingqApp->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 firstif (currKeyBindInfo.first != NULL) {currKeyBindInfo.first->setText("Hotkey: None");currKeyBindInfo.first->setDown(false);currKeyBindInfo.first->removeEventFilter(this);}// Mark and save button as waiting for key sequencebtn->setDown(true);btn->setText("Waiting for Key..");currKeyBindInfo = QPair<QPushButton*,int>(btn, id);// Remove current keybinding for this macroint index = registeredKeyMacroIDs.indexOf(id);if (index >= 0) {registeredKeySequences.removeAt(index);registeredKeyMacroIDs.removeAt(index);}// Inspect all following keyboard eventsbtn->installEventFilter(this);}void MacroWidget::Macro_AddEntry(){macroCount++;// Create new layout/widgetsQLineEdit *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 layoutmainLayout->addLayout(tmpLayout, macroCount, 0);mainLayout->addWidget(textEdit, macroCount, 1);mainLayout->setColumnStretch(1, 1);// Associate KeyButton with its corresponding IDsigmapKeybind->setMapping(keyButton, macroCount-1);connect(keyButton, SIGNAL(clicked()), sigmapKeybind, SLOT(map()));// Associate PushButton with its corresponding TextEditsigmapTransmit->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 slotQLayoutItem *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 listsQPushButton *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 closeif (file.size() == 0) return;// If file was selected, save directory for next timeQFileInfo 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(); // Macrostream.writeEndElement(); // Settingsstream.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 closeif (file.size() == 0) return;Macro_Clear();// If file was selected, save directory for next timeQFileInfo 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 StartDocumentif (token == QXmlStreamReader::StartDocument) continue;// Parse StartElementsif (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 valueQXmlStreamAttributes attr = stream.attributes();if (attr.hasAttribute("Name"))name = attr.value("Name").toString();stream.readNext();// Loop in this element to find all sub-elementswhile (!(stream.tokenType() == QXmlStreamReader::EndElement && stream.name() == "Macro_Entry")) {// Parse and save element valueif (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 GUIif (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 eventsif (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 onesif (!registeredKeySequences.isEmpty()) {int index = registeredKeySequences.indexOf(seq);if (index >= 0) {Macro_InitTransmit(macroValueList[registeredKeyMacroIDs[index]]);return true;}}}// Then save key sequence if neededif (currKeyBindInfo.first != NULL) {// Ignore modifier keys and locksif (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 keyif (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 existif (!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);}