Subversion Repositories Code-Repo

Rev

Rev 364 | Blame | Last modification | View Log | RSS feed

#include "PasteController.h"

PasteController::PasteController(QWidget *parent) : QWidget(parent)
{
    connected = false;
    hotkeysEnabled = false;
    xPos = yPos = zPos = 0.0;
    X_Incr = X_Decr = Y_Incr = Y_Decr = Z_Incr = Z_Decr = E_Incr = false;

    transmittingData = false;
    queueCmds = new QQueue<QString>();

    tmrUpdate = new QTimer(this);
    connect(tmrUpdate, SIGNAL(timeout()), this, SLOT(MoveToolhead()));

    QString helpString = "";
    helpString.append("XY Control: Arrow Keys or H/J/K/L\n");
    helpString.append("Z Control: PgUp/PgDown\n");
    helpString.append(" - Hold Shift for Slower Movement\n");
    helpString.append("Extruder Trigger: Space");
    labelHelp = new QLabel(helpString);

    QVBoxLayout *helpLayout = new QVBoxLayout();
    helpLayout->addWidget(labelHelp);

    QGroupBox *helpBox = new QGroupBox("Hotkeys:");
    helpBox->setLayout(helpLayout);

    btnEnableHotkeys = new QPushButton("&Enable Hotkeys");
    connect(btnEnableHotkeys, SIGNAL(clicked()), this, SLOT(ToggleHotkeys()));

    btnInit = new QPushButton("&Initialize Printer");
    connect(btnInit, SIGNAL(clicked()), this, SLOT(InitializePrinter()));

    btnHome = new QPushButton("&Home Printhead");
    connect(btnHome, SIGNAL(clicked()), this, SLOT(ResetPosition()));

    QVBoxLayout *miscBtnLayout = new QVBoxLayout();
    miscBtnLayout->addWidget(btnInit);
    miscBtnLayout->addWidget(btnEnableHotkeys);
    miscBtnLayout->addWidget(btnHome);

    QGroupBox *miscBtnBox = new QGroupBox("Preset Commands");
    miscBtnBox->setLayout(miscBtnLayout);
    miscBtnBox->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Maximum);

    // Icons from http://ikons.piotrkwiatkowski.co.uk/index.html
    QIcon iconUp(":/External/Resources/arrow_up.png");
    QIcon iconDown(":/External/Resources/arrow_down.png");
    QIcon iconLeft(":/External/Resources/arrow_left.png");
    QIcon iconRight(":/External/Resources/arrow_right.png");
    QIcon iconAdd(":/External/Resources/upload.png");
    QIcon iconRemove(":/External/Resources/download.png");
    QIcon iconDelete(":/External/Resources/close.png");

    btnForward = new QToolButton();
    btnForward->setIcon(iconUp);
    btnForward->setIconSize(QSize(BTN_ICON_SIZE,BTN_ICON_SIZE));
    btnForward->setAutoRaise(true);
    connect(btnForward, SIGNAL(clicked()), this, SLOT(MoveToolheadSingle()));
    btnBackward = new QToolButton();
    btnBackward->setIcon(iconDown);
    btnBackward->setIconSize(QSize(BTN_ICON_SIZE,BTN_ICON_SIZE));
    btnBackward->setAutoRaise(true);
    connect(btnBackward, SIGNAL(clicked()), this, SLOT(MoveToolheadSingle()));
    btnLeft = new QToolButton();
    btnLeft->setIcon(iconLeft);
    btnLeft->setIconSize(QSize(BTN_ICON_SIZE,BTN_ICON_SIZE));
    btnLeft->setAutoRaise(true);
    connect(btnLeft, SIGNAL(clicked()), this, SLOT(MoveToolheadSingle()));
    btnRight = new QToolButton();
    btnRight->setIcon(iconRight);
    btnRight->setIconSize(QSize(BTN_ICON_SIZE,BTN_ICON_SIZE));
    btnRight->setAutoRaise(true);
    connect(btnRight, SIGNAL(clicked()), this, SLOT(MoveToolheadSingle()));
    btnUp = new QToolButton();
    btnUp->setIcon(iconAdd);
    btnUp->setIconSize(QSize(BTN_ICON_SIZE,BTN_ICON_SIZE));
    btnUp->setAutoRaise(true);
    connect(btnUp, SIGNAL(clicked()), this, SLOT(MoveToolheadSingle()));
    btnDown = new QToolButton();
    btnDown->setIcon(iconRemove);
    btnDown->setIconSize(QSize(BTN_ICON_SIZE,BTN_ICON_SIZE));
    btnDown->setAutoRaise(true);
    connect(btnDown, SIGNAL(clicked()), this, SLOT(MoveToolheadSingle()));
    btnExtrude = new QToolButton();
    btnExtrude->setIcon(iconDelete);
    btnExtrude->setIconSize(QSize(BTN_ICON_SIZE,BTN_ICON_SIZE));
    btnExtrude->setAutoRaise(true);
    connect(btnExtrude, SIGNAL(clicked()), this, SLOT(ExtrudeSingle()));

    QGridLayout *btnXYELayout = new QGridLayout();
    btnXYELayout->addWidget(btnForward, 0, 1, 1, 1);
    btnXYELayout->addWidget(btnLeft, 1, 0, 1, 1);
    btnXYELayout->addWidget(btnExtrude, 1, 1, 1, 1);
    btnXYELayout->addWidget(btnRight, 1, 2, 1, 1);
    btnXYELayout->addWidget(btnBackward, 2, 1, 1, 1);

    QVBoxLayout *btnZLayout = new QVBoxLayout();
    btnZLayout->addWidget(btnUp);
    btnZLayout->addWidget(btnDown);

    QHBoxLayout *btnNavLayout = new QHBoxLayout();
    btnNavLayout->addLayout(btnXYELayout);
    btnNavLayout->addLayout(btnZLayout);

    QGroupBox *controlBox = new QGroupBox("Manual Printer Control");
    controlBox->setLayout(btnNavLayout);
    controlBox->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);

    labelXPos = new QLabel("X :");
    labelXPos->setFont(QFont("", 14, QFont::Normal));
    labelYPos = new QLabel("Y :");
    labelYPos->setFont(QFont("", 14, QFont::Normal));
    labelZPos = new QLabel("Z :");
    labelZPos->setFont(QFont("", 14, QFont::Normal));
    textXValue = new QLineEdit();
    textXValue->setReadOnly(true);
    textXValue->setMaximumWidth(60);
    textXValue->setFont(QFont("", 10, QFont::Bold));
    textXValue->setAlignment(Qt::AlignCenter);
    textXValue->setText(QString::number(xPos, 'f', 2));
    textYValue = new QLineEdit();
    textYValue->setReadOnly(true);
    textYValue->setMaximumWidth(60);
    textYValue->setFont(QFont("", 10, QFont::Bold));
    textYValue->setAlignment(Qt::AlignCenter);
    textYValue->setText(QString::number(yPos, 'f', 2));
    textZValue = new QLineEdit();
    textZValue->setReadOnly(true);
    textZValue->setMaximumWidth(60);
    textZValue->setFont(QFont("", 10, QFont::Bold));
    textZValue->setAlignment(Qt::AlignCenter);
    textZValue->setText(QString::number(zPos, 'f', 2));

    QHBoxLayout *posValueLayout = new QHBoxLayout();
    posValueLayout->addWidget(labelXPos);
    posValueLayout->addWidget(textXValue);
    posValueLayout->addWidget(labelYPos);
    posValueLayout->addWidget(textYValue);
    posValueLayout->addWidget(labelZPos);
    posValueLayout->addWidget(textZValue);

    QGroupBox *toolheadPosBox = new QGroupBox("Toolhead Position");
    toolheadPosBox->setLayout(posValueLayout);
    toolheadPosBox->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);

    labelXYSteps = new QLabel("XY Axis Step (mm):");
    sliderXYSteps = new QSlider(Qt::Horizontal);
    textXYSteps = new QDoubleSpinBox();
    textXYSteps->setMinimumWidth(60);
    labelXYSpeed = new QLabel("XY Axis Speed (mm/s):");
    sliderXYSpeed = new QSlider(Qt::Horizontal);
    textXYSpeed = new QSpinBox();
    textXYSpeed->setMinimumWidth(60);
    labelZSteps = new QLabel("Z Axis Step (mm):");
    sliderZSteps = new QSlider(Qt::Horizontal);
    textZSteps = new QDoubleSpinBox();
    textZSteps->setMinimumWidth(60);
    labelZSpeed = new QLabel("Z Axis Speed (mm/s):");
    sliderZSpeed = new QSlider(Qt::Horizontal);
    textZSpeed = new QSpinBox();
    textZSpeed->setMinimumWidth(60);
    labelRepeatDelay = new QLabel("Repeat Delay (ms):");
    sliderRepeatDelay = new QSlider(Qt::Horizontal);
    textRepeatDelay = new QSpinBox();
    textRepeatDelay->setMinimumWidth(60);

    labelEForwardSteps = new QLabel("Extrude Step (mm):");
    sliderEForwardSteps = new QSlider(Qt::Horizontal);
    textEForwardSteps = new QDoubleSpinBox();
    textEForwardSteps->setMinimumWidth(60);
    labelEForwardSpeed = new QLabel("Extrude Speed (mm/s):");
    sliderEForwardSpeed = new QSlider(Qt::Horizontal);
    textEForwardSpeed = new QSpinBox();
    textEForwardSpeed->setMinimumWidth(60);
    labelEBackwardSteps = new QLabel("Retract Step (mm):");
    sliderEBackwardSteps = new QSlider(Qt::Horizontal);
    textEBackwardSteps = new QDoubleSpinBox();
    textEBackwardSteps->setMinimumWidth(60);
    labelEBackwardSpeed = new QLabel("Retract Speed: (mm/s)");
    sliderEBackwardSpeed = new QSlider(Qt::Horizontal);
    textEBackwardSpeed = new QSpinBox();
    textEBackwardSpeed->setMinimumWidth(60);
    labelExtrusionHeight = new QLabel("Extrude Height (mm):");
    sliderExtrusionHeight = new QSlider(Qt::Horizontal);
    textExtrusionHeight = new QDoubleSpinBox();
    textExtrusionHeight->setMinimumWidth(60);
    labelEZSteps = new QLabel("Z Axis Step (mm):");
    sliderEZSteps = new QSlider(Qt::Horizontal);
    textEZSteps = new QDoubleSpinBox();
    textEZSteps->setMinimumWidth(60);

    connect(sliderXYSteps, SIGNAL(valueChanged(int)), this, SLOT(QSliderToQDoubleSpinBox(int)));
    connect(textXYSteps, SIGNAL(valueChanged(double)), this, SLOT(QDoubleSpinBoxToQSlider(double)));
    sliderXYSteps->setRange(0, 1000);
    textXYSteps->setRange(0,10);
    textXYSteps->setSingleStep(0.1);
    textXYSteps->setValue(0.5);
    connect(sliderXYSpeed, SIGNAL(valueChanged(int)), textXYSpeed, SLOT(setValue(int)));
    connect(textXYSpeed, SIGNAL(valueChanged(int)), sliderXYSpeed, SLOT(setValue(int)));
    sliderXYSpeed->setRange(1, 4000);
    textXYSpeed->setRange(1, 4000);
    textXYSpeed->setSingleStep(100);
    textXYSpeed->setValue(600);
    connect(sliderZSteps, SIGNAL(valueChanged(int)), this, SLOT(QSliderToQDoubleSpinBox(int)));
    connect(textZSteps, SIGNAL(valueChanged(double)), this, SLOT(QDoubleSpinBoxToQSlider(double)));
    sliderZSteps->setRange(0, 1000);
    textZSteps->setRange(0, 10);
    textZSteps->setSingleStep(0.1);
    textZSteps->setValue(0.5);
    connect(sliderZSpeed, SIGNAL(valueChanged(int)), textZSpeed, SLOT(setValue(int)));
    connect(textZSpeed, SIGNAL(valueChanged(int)), sliderZSpeed, SLOT(setValue(int)));
    sliderZSpeed->setRange(1, 1000);
    textZSpeed->setRange(1, 1000);
    textZSpeed->setSingleStep(100);
    textZSpeed->setValue(400);
    connect(sliderRepeatDelay, SIGNAL(valueChanged(int)), textRepeatDelay, SLOT(setValue(int)));
    connect(textRepeatDelay, SIGNAL(valueChanged(int)), sliderRepeatDelay, SLOT(setValue(int)));
    sliderRepeatDelay->setRange(1, 200);
    textRepeatDelay->setRange(1, 200);
    textRepeatDelay->setValue(45);

    QGridLayout *xyRepeatLayout = new QGridLayout();
    xyRepeatLayout->addWidget(labelXYSteps, 0, 0);
    xyRepeatLayout->addWidget(sliderXYSteps, 0, 1);
    xyRepeatLayout->addWidget(textXYSteps, 0, 2);
    xyRepeatLayout->addWidget(labelXYSpeed, 1, 0);
    xyRepeatLayout->addWidget(sliderXYSpeed, 1, 1);
    xyRepeatLayout->addWidget(textXYSpeed, 1, 2);
    xyRepeatLayout->addWidget(labelZSteps, 2, 0);
    xyRepeatLayout->addWidget(sliderZSteps, 2, 1);
    xyRepeatLayout->addWidget(textZSteps, 2, 2);
    xyRepeatLayout->addWidget(labelZSpeed, 3, 0);
    xyRepeatLayout->addWidget(sliderZSpeed, 3, 1);
    xyRepeatLayout->addWidget(textZSpeed, 3, 2);
    xyRepeatLayout->addWidget(labelRepeatDelay, 4, 0);
    xyRepeatLayout->addWidget(sliderRepeatDelay, 4, 1);
    xyRepeatLayout->addWidget(textRepeatDelay, 4, 2);

    QGroupBox *xyRepeatBox = new QGroupBox("Movement Settings");
    xyRepeatBox->setLayout(xyRepeatLayout);

    connect(sliderEForwardSteps, SIGNAL(valueChanged(int)), this, SLOT(QSliderToQDoubleSpinBox(int)));
    connect(textEForwardSteps, SIGNAL(valueChanged(double)), this, SLOT(QDoubleSpinBoxToQSlider(double)));
    sliderEForwardSteps->setRange(0, 10000);
    textEForwardSteps->setRange(0, 100);
    textEForwardSteps->setSingleStep(0.1);
    textEForwardSteps->setValue(8);
    connect(sliderEForwardSpeed, SIGNAL(valueChanged(int)), textEForwardSpeed, SLOT(setValue(int)));
    connect(textEForwardSpeed, SIGNAL(valueChanged(int)), sliderEForwardSpeed, SLOT(setValue(int)));
    sliderEForwardSpeed->setRange(1, 10000);
    textEForwardSpeed->setRange(1, 10000);
    textEForwardSpeed->setSingleStep(100);
    textEForwardSpeed->setValue(800);
    connect(sliderEBackwardSteps, SIGNAL(valueChanged(int)), this, SLOT(QSliderToQDoubleSpinBox(int)));
    connect(textEBackwardSteps, SIGNAL(valueChanged(double)), this, SLOT(QDoubleSpinBoxToQSlider(double)));
    sliderEBackwardSteps->setRange(0, 10000);
    textEBackwardSteps->setRange(0, 100);
    textEBackwardSteps->setSingleStep(0.1);
    textEBackwardSteps->setValue(2);
    connect(sliderEBackwardSpeed, SIGNAL(valueChanged(int)), textEBackwardSpeed, SLOT(setValue(int)));
    connect(textEBackwardSpeed, SIGNAL(valueChanged(int)), sliderEBackwardSpeed, SLOT(setValue(int)));
    sliderEBackwardSpeed->setRange(1, 10000);
    textEBackwardSpeed->setRange(1, 10000);
    textEBackwardSpeed->setSingleStep(100);
    textEBackwardSpeed->setValue(1600);
    connect(sliderExtrusionHeight, SIGNAL(valueChanged(int)), this, SLOT(QSliderToQDoubleSpinBox(int)));
    connect(textExtrusionHeight, SIGNAL(valueChanged(double)), this, SLOT(QDoubleSpinBoxToQSlider(double)));
    connect(textExtrusionHeight, SIGNAL(valueChanged(double)), this, SLOT(SetBaseHeight()));
    sliderExtrusionHeight->setRange(0, 400);
    textExtrusionHeight->setRange(0, 4);
    textExtrusionHeight->setSingleStep(0.1);
    textExtrusionHeight->setValue(2);
    connect(sliderEZSteps, SIGNAL(valueChanged(int)), this, SLOT(QSliderToQDoubleSpinBox(int)));
    connect(textEZSteps, SIGNAL(valueChanged(double)), this, SLOT(QDoubleSpinBoxToQSlider(double)));
    connect(textEZSteps, SIGNAL(valueChanged(double)), this, SLOT(SetBaseHeight()));
    sliderEZSteps->setRange(0, 1000);
    textEZSteps->setRange(0, 10);
    textEZSteps->setSingleStep(0.1);
    textEZSteps->setValue(2);

    QGridLayout *extruderLayout = new QGridLayout();
    extruderLayout->addWidget(labelEForwardSteps, 0, 0);
    extruderLayout->addWidget(sliderEForwardSteps, 0, 1);
    extruderLayout->addWidget(textEForwardSteps, 0, 2);
    extruderLayout->addWidget(labelEForwardSpeed, 1, 0);
    extruderLayout->addWidget(sliderEForwardSpeed, 1, 1);
    extruderLayout->addWidget(textEForwardSpeed, 1, 2);
    extruderLayout->addWidget(labelEBackwardSteps, 2, 0);
    extruderLayout->addWidget(sliderEBackwardSteps, 2, 1);
    extruderLayout->addWidget(textEBackwardSteps, 2, 2);
    extruderLayout->addWidget(labelEBackwardSpeed, 4, 0);
    extruderLayout->addWidget(sliderEBackwardSpeed, 4, 1);
    extruderLayout->addWidget(textEBackwardSpeed, 4, 2);
    extruderLayout->addWidget(labelExtrusionHeight, 5, 0);
    extruderLayout->addWidget(sliderExtrusionHeight, 5, 1);
    extruderLayout->addWidget(textExtrusionHeight, 5, 2);
    extruderLayout->addWidget(labelEZSteps, 6, 0);
    extruderLayout->addWidget(sliderEZSteps, 6, 1);
    extruderLayout->addWidget(textEZSteps, 6, 2);

    QGroupBox *extruderBox = new QGroupBox("Extruder Settings");
    extruderBox->setLayout(extruderLayout);

    QVBoxLayout *column1Layout = new QVBoxLayout();
    column1Layout->addWidget(controlBox, 0, Qt::AlignTop);
    column1Layout->addWidget(miscBtnBox, 0, Qt::AlignTop);
    column1Layout->addWidget(helpBox, 1, Qt::AlignTop);

    QVBoxLayout *column2Layout = new QVBoxLayout();
    column2Layout->addWidget(toolheadPosBox);
    column2Layout->addWidget(xyRepeatBox);
    column2Layout->addWidget(extruderBox);

    QHBoxLayout *mainLayout = new QHBoxLayout();
    mainLayout->addLayout(column1Layout);
    mainLayout->addLayout(column2Layout);

    EnableTransmit(false);

    setLayout(mainLayout);
    setFixedSize(sizeHint());
}

PasteController::~PasteController()
{

}

void PasteController::EnableTransmit(bool en) {
    connected = en;
    btnEnableHotkeys->setEnabled(en);
    btnInit->setEnabled(en);
    btnHome->setEnabled(en);
    btnForward->setEnabled(en);
    btnBackward->setEnabled(en);
    btnLeft->setEnabled(en);
    btnRight->setEnabled(en);
    btnDown->setEnabled(en);
    btnUp->setEnabled(en);
    btnExtrude->setEnabled(en);
}

void PasteController::InitializePrinter() {
    queueCmds->enqueue("G90\n");        // Absolute positioning
    queueCmds->enqueue("M83\n");        // Relative extrusion
    queueCmds->enqueue("M204 S3000");   // Default acceleration (movement)
    queueCmds->enqueue("M205 X10");     // Maximum XY jerk
    queueCmds->enqueue("M302");         // Allow cold extrusions

    if (!transmittingData) {
        transmittingData = true;
        emit TransmitData(queueCmds->head().toUtf8());
    }

    ResetPosition();
    SetBaseHeight();
}

void PasteController::ToggleHotkeys() {
    if (hotkeysEnabled) {
        qApp->removeEventFilter(this);
        btnEnableHotkeys->setText("&Enable Hotkeys");
    } else {
        qApp->installEventFilter(this);
        btnEnableHotkeys->setText("&Disable Hotkeys");
    }
    hotkeysEnabled = !hotkeysEnabled;
}

void PasteController::MoveToolhead() {
    if (X_Incr && !X_Decr)
        xPos = (xPos + textXYSteps->value() < X_MAX) ? xPos + textXYSteps->value() : X_MAX;
    if (!X_Incr && X_Decr)
        xPos = (xPos - textXYSteps->value() > X_MIN) ? xPos - textXYSteps->value() : X_MIN;
    if (Y_Incr && !Y_Decr)
        yPos = (yPos + textXYSteps->value() < Y_MAX) ? yPos + textXYSteps->value() : Y_MAX;
    if (!Y_Incr && Y_Decr)
        yPos = (yPos - textXYSteps->value() > Y_MIN) ? yPos - textXYSteps->value() : Y_MIN;
    if (Z_Incr && !Z_Decr)
        zPos = (zPos + textZSteps->value() < Z_MAX) ? zPos + textZSteps->value() : Z_MAX;
    if (!Z_Incr && Z_Decr)
        zPos = (zPos - textZSteps->value() > Z_MIN) ? zPos - textZSteps->value() : Z_MIN;

    UpdatePosition();

    QString str;
    QTextStream strIO(&str);
    if (Z_Incr || Z_Decr) {
        strIO << "G0";
        strIO << " Z" << zPos;
        strIO << " F" << textZSpeed->value();
        strIO << "\n";
    } else {
        strIO << "G0";
        strIO << " X" << xPos;
        strIO << " Y" << yPos;
        strIO << " F" << textXYSpeed->value();
        strIO << "\n";
    }

    queueCmds->enqueue(str);
    if (!transmittingData) {
        transmittingData = true;
        emit TransmitData(queueCmds->head().toUtf8());
    }
}

void PasteController::MoveToolheadSingle() {
    if (QObject::sender() == btnRight) xPos += textXYSteps->value();
    if (QObject::sender() == btnLeft) xPos -= textXYSteps->value();
    if (QObject::sender() == btnForward) yPos += textXYSteps->value();
    if (QObject::sender() == btnBackward) yPos -= textXYSteps->value();
    if (QObject::sender() == btnUp) zPos += textZSteps->value();
    if (QObject::sender() == btnDown) zPos -= textZSteps->value();

    UpdatePosition();

    QString str;
    QTextStream strIO(&str);
    if (QObject::sender() == btnRight || QObject::sender() == btnLeft ||
        QObject::sender() == btnForward || QObject::sender() == btnBackward) {
        strIO << "G0";
        strIO << " X" << xPos;
        strIO << " Y" << yPos;
        strIO << " F" << textXYSpeed->value();
        strIO << "\n";
    } else if (QObject::sender() == btnUp || QObject::sender() == btnDown) {
        strIO << "G0";
        strIO << " Z" << zPos;
        strIO << " F" << textZSpeed->value();
        strIO << "\n";
    }

    queueCmds->enqueue(str);
    if (!transmittingData) {
        transmittingData = true;
        emit TransmitData(queueCmds->head().toUtf8());
    }
}

void PasteController::UpdatePosition() {
    textXValue->setText(QString::number(xPos, 'f', 2));
    textYValue->setText(QString::number(yPos, 'f', 2));
    textZValue->setText(QString::number(zPos, 'f', 2));
}

void PasteController::ExtrudeSingle() {
    QString str;
    // Move printdown down
    str = "G0 Z" + QString::number(textExtrusionHeight->value()) +
          " F" + QString::number(textZSpeed->value()) + "\n";
    zPos = textExtrusionHeight->value();
    queueCmds->enqueue(str);

    // Extrude paste
    str = "G0 E-" + QString::number(textEForwardSteps->value()) +
          " F" + QString::number(textEForwardSpeed->value()) + "\n";
    queueCmds->enqueue(str);

    // Retract paste
    str = "G0 E" + QString::number(textEBackwardSteps->value()) +
          " F" + QString::number(textEBackwardSpeed->value()) + "\n";
    queueCmds->enqueue(str);

    // Move printhead up
    str = "G0 Z" + QString::number(textEZSteps->value() + textExtrusionHeight->value()) +
          " F" + QString::number(textZSpeed->value()) + "\n";
    zPos = textEZSteps->value() + textExtrusionHeight->value();
    queueCmds->enqueue(str);

    if (!transmittingData) {
        transmittingData = true;
        emit TransmitData(queueCmds->head().toUtf8());
    }
}

void PasteController::ResetPosition() {
    xPos = yPos = zPos = 0;

    queueCmds->enqueue("G28\n");        // Home printhead
    if (!transmittingData) {
        transmittingData = true;
        emit TransmitData(queueCmds->head().toUtf8());
    }

    MoveToolhead();
}

void PasteController::ProcessData(QByteArray data) {
    static QString recvData;
    if (transmittingData) {
        // Need to wait for acknowledgement from the printer after each command
        recvData.append(QString(data));
        while (recvData.indexOf('\n') != -1) {
            QString ret = recvData.left(recvData.indexOf('\n')+1);
            recvData.remove(0, recvData.indexOf('\n')+1);
            bool transmit = false;
            if (ret.startsWith("ok")) {
                // Last command successfully processed
                queueCmds->dequeue();
                transmit = true;
            } else if (ret.startsWith("rs" || ret.startsWith("Resend"))) {
                transmit = true;
            } else if (ret.startsWith("!!" || ret.startsWith("Error"))) {
                emit UpdateStatus("Hardware fault detected!");
                queueCmds->clear();
            } else if (ret.startsWith("echo")) {
                // Ignore anything else sent
            }
            if (transmit && !queueCmds->isEmpty()) {
                emit TransmitData(queueCmds->head().toUtf8());
            } else if (queueCmds->isEmpty()){
                transmittingData = false;
            }
        }
    }
}

void PasteController::SetBaseHeight() {
    if (connected) {
        QString str = "G0 Z" + QString::number(textEZSteps->value() + textExtrusionHeight->value()) +
              " F" + QString::number(textZSpeed->value()) + "\n";
        zPos = textEZSteps->value() + textExtrusionHeight->value();
        queueCmds->enqueue(str);

        if (!transmittingData) {
            transmittingData = true;
            emit TransmitData(queueCmds->head().toUtf8());
        }
        UpdatePosition();
    }
}

void PasteController::QSliderToQDoubleSpinBox(int) {
    textXYSteps->setValue((double)sliderXYSteps->value()/100);
    textZSteps->setValue((double)sliderZSteps->value()/100);
    textEZSteps->setValue((double)sliderEZSteps->value()/100);
    textEForwardSteps->setValue((double)sliderEForwardSteps->value()/100);
    textEBackwardSteps->setValue((double)sliderEBackwardSteps->value()/100);
    textExtrusionHeight->setValue((double)sliderExtrusionHeight->value()/100);
}

void PasteController::QDoubleSpinBoxToQSlider(double) {
    sliderXYSteps->setValue(textXYSteps->value()*100);
    sliderZSteps->setValue(textZSteps->value()*100);
    sliderEZSteps->setValue(textEZSteps->value()*100);
    sliderEForwardSteps->setValue((double)textEForwardSteps->value()*100);
    sliderEBackwardSteps->setValue((double)textEBackwardSteps->value()*100);
    sliderExtrusionHeight->setValue((double)textExtrusionHeight->value()*100);
}

bool PasteController::eventFilter(QObject *obj, QEvent *event)
{
    // Only process keyboard press and release events
    if (event->type() == QEvent::KeyPress) {
        QKeyEvent *keyevent = static_cast<QKeyEvent*>(event);
//        QKeySequence seq = keyevent->modifiers() + keyevent->key();

        if (hotkeysEnabled) {
            if (keyevent->isAutoRepeat()) return true;
            bool keychange = false;
            if (keyevent->key() == Qt::Key_Left || keyevent->key() == Qt::Key_H) {
                btnLeft->setDown(true);
                X_Decr = keychange = true;
            }
            if (keyevent->key() == Qt::Key_Right || keyevent->key() == Qt::Key_L) {
                btnRight->setDown(true);
                X_Incr = keychange = true;
            }
            if (keyevent->key() == Qt::Key_Up || keyevent->key() == Qt::Key_K) {
                btnForward->setDown(true);
                Y_Incr = keychange = true;
            }
            if (keyevent->key() == Qt::Key_Down || keyevent->key() == Qt::Key_J) {
                btnBackward->setDown(true);
                Y_Decr = keychange = true;
            }
            if (keyevent->key() == Qt::Key_PageDown) {
                btnDown->setDown(true);
                Z_Decr = keychange = true;
            }
            if (keyevent->key() == Qt::Key_PageUp) {
                btnUp->setDown(true);
                Z_Incr = keychange = true;
            }
            if (keyevent->key() == Qt::Key_Space) {
                btnExtrude->setDown(true);
                E_Incr = keychange = true;
            }
            if (E_Incr) {
                ExtrudeSingle();
            } else if (X_Incr || X_Decr || Y_Incr || Y_Decr || Z_Incr || Z_Decr) {
                MoveToolhead();
                if (keyevent->modifiers() == Qt::ShiftModifier) {
                    tmrUpdate->start(textRepeatDelay->value() * SLOW_MULTIPLIER);
                } else {
                    tmrUpdate->start(textRepeatDelay->value());
                }
            }
            if (keychange) return true;
        }
    } else if (event->type() == QEvent::KeyRelease) {
        QKeyEvent *keyevent = static_cast<QKeyEvent*>(event);
//        QKeySequence seq = keyevent->modifiers() + keyevent->key();

        if (hotkeysEnabled) {
            if (keyevent->isAutoRepeat()) return true;
            bool keychange = false;
            if (keyevent->key() == Qt::Key_Left || keyevent->key() == Qt::Key_H) {
                btnLeft->setDown(false);
                X_Decr = keychange = false;
            }
            if (keyevent->key() == Qt::Key_Right || keyevent->key() == Qt::Key_L) {
                btnRight->setDown(false);
                X_Incr = keychange = false;
            }
            if (keyevent->key() == Qt::Key_Up || keyevent->key() == Qt::Key_K) {
                btnForward->setDown(false);
                Y_Incr = keychange = false;
            }
            if (keyevent->key() == Qt::Key_Down || keyevent->key() == Qt::Key_J) {
                btnBackward->setDown(false);
                Y_Decr = keychange = false;
            }
            if (keyevent->key() == Qt::Key_PageDown) {
                btnDown->setDown(false);
                Z_Decr = keychange = false;
            }
            if (keyevent->key() == Qt::Key_PageUp) {
                btnUp->setDown(false);
                Z_Incr = keychange = false;
            }
            if (keyevent->key() == Qt::Key_Space) {
                btnExtrude->setDown(false);
                E_Incr = keychange = false;
            }
            if (!X_Incr && !X_Decr && !Y_Incr && !Y_Decr && !Z_Incr && !Z_Decr) {
                tmrUpdate->stop();
            }
            if (keychange) return true;
        }
    }

    return QWidget::eventFilter(obj, event);
}