Subversion Repositories Code-Repo

Rev

Blame | Last modification | View Log | RSS feed

#include "Gate_BASE.h"

Gate_BASE::Gate_BASE(int gateID, gType gateType,
                     int numInputs, int gateLevel,
                     QGraphicsItem *parent) :
    QGraphicsObject(parent)
{
    setFlags(ItemIsSelectable);

    auxSelected = false;

    this->gateID = gateID;
    this->gateType = gateType;
    this->numInputs = numInputs;
    this->gateLevel = gateLevel;
    this->enqueued = false;

    this->xSize = BASE_GATE_SIZE_X + ADDITONAL_INPUTS * qMax(numInputs, 1);
    this->ySize = BASE_GATE_SIZE_Y + ADDITONAL_INPUTS * qMax(numInputs, 1);

    // Create the default pens to draw with
    this->defaultPen = QPen(QColor(COLOR_MAIN), DEFAULT_LINE_WIDTH, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
    this->defaultBrush = QBrush(Qt::NoBrush);
    this->defaultFont = QFont("Consolas", 20);
    this->selectedPen = QPen(QColor(COLOR_MAIN_SELECTED), DEFAULT_LINE_WIDTH, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
    this->highlightedPen = QPen(QColor(COLOR_MAIN_SELECTED), DEFAULT_LINE_WIDTH, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);

    // Calculate local and global points for inputs
    float spacer = float(this->ySize - BORDER_OFFSET * 2) / (numInputs + 1);
    for (int i = 0; i < numInputs; i++) {
        QPointF point = QPointF(0, this->ySize - BORDER_OFFSET - (spacer * i + spacer));
        this->inputPoints.push_back(point);
        QPointF scenePoint = QPointF(this->scenePos().x(), this->scenePos().y() - BORDER_OFFSET - (spacer * i + spacer));
        this->gateInputPoints.push_back(scenePoint);
    }

    // Output point will always be centered on the right edge
    this->outputPoint = QPointF(this->xSize, this->ySize / 2);
    this->gateOutputPoint = QPointF(this->scenePos().x() + this->xSize, this->scenePos().y() + this->ySize / 2);

    // Reset I/O values to 'X'
    for (int i = 0; i < numInputs; i++) {
        inputValues.append(logicValue_X);
        inputFaultyValues.append(logicValue_X);
    }
    outputValue = logicValue_X;
    outputFaultyValue = logicValue_X;

#ifdef _DEBUG
        this->debugPen = QPen(QColor(COLOR_DEBUG), 1, Qt::DashLine);
        this->debugBrush = QBrush(Qt::NoBrush);
        this->debugSelectedPen = QPen(QColor(COLOR_DEBUG_SELECTED), 1, Qt::DashLine);
        this->debugErrorPen = QPen(QColor(COLOR_DEBUG_ERROR), 2, Qt::DashLine);
#endif
}

Gate_BASE::~Gate_BASE()
{

}

QRectF Gate_BASE::boundingRect() const
{
    return QRectF(0, 0, xSize, ySize);
}

QPainterPath Gate_BASE::shape() const
{
    QPainterPath path;
    path.addRect(BORDER_OFFSET, BORDER_OFFSET, xSize - BORDER_OFFSET * 2, ySize - BORDER_OFFSET * 2);
    return path;
}

/**
 * Sets the position of this gate (centered) on the scene
 */
void Gate_BASE::setCanvasPosition(int x, int y)
{
    canvasPoint.setX(x);
    canvasPoint.setY(y);

    // Canvas position correlates to the center of the gate
    this->setPos(x - xSize / 2, y - ySize / 2);

    // Calculate points for inputs
    float spacer = float(this->ySize - BORDER_OFFSET * 2) / (numInputs + 1);
    this->gateInputPoints.clear();
    for (int i = 0; i < numInputs; i++) {
        QPointF scenePoint = QPointF(this->scenePos().x(), this->scenePos().y() + BORDER_OFFSET + (spacer * i + spacer));
        this->gateInputPoints.push_back(scenePoint);
    }

    // Output point will always be centered on the right edge
    this->gateOutputPoint = QPointF(this->scenePos().x() + this->xSize, this->scenePos().y() + this->ySize / 2);
}

/**
 * Sets the color of the drawing pen
 */
void Gate_BASE::setHighlight(bool state, QColor color)
{
    auxSelected = state;
    if (state) {
        highlightedPen.setColor(color);
        setZValue(SELECTED_Z);
    } else {
        setZValue(GATE_DEFAULT_Z);
    }
    update();
}

/**
 * Resets the gate's value to unknown 'X'
 */
void Gate_BASE::reset()
{
    // Reset I/O values to 'X'
    for (int i = 0; i < numInputs; i++) {
        inputValues[i] = logicValue_X;
        inputFaultyValues[i] = logicValue_X;
    }
    outputValue = logicValue_X;
    outputFaultyValue = logicValue_X;

    // Reset connected wires
    for (int i = 0; i < gateInputWires.size(); i++)
        gateInputWires[i]->setValue(logicValue_X, logicValue_X, false);
    for (int i = 0; i < gateOutputWires.size(); i++)
        gateOutputWires[i]->setValue(logicValue_X, logicValue_X, false);

    enqueued = false;
    update();
}

/**
 * Sets a specific input to this gate
 */
void Gate_BASE::setInputValue(int input, logicValue value, logicValue faultyValue)
{
    // If the input has changed, queue this gate for simulation
    if (inputValues[input] != value || inputFaultyValues[input] != faultyValue)
        emit enqueueSim(this);

    inputValues[input] = value;
    inputFaultyValues[input] = faultyValue;
}

/**
 * Sets the output value of this gate
 */
void Gate_BASE::setOutputValue(logicValue value, logicValue faultyValue)
{
    outputValue = value;
    outputFaultyValue = faultyValue;
}

/**
 * Updates flag to indicate queued status
 */
void Gate_BASE::setEnqueued(bool value)
{
    enqueued = value;
    update();
}

void Gate_BASE::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    // Update status bar with information on this gate
    QString status = QString("Gate %1 ").arg(gateID);
    if (fanInGates.size() != 0)
        status += "| Input Gates: ";
        for (int i = 0; i < fanInGates.size(); i++) {
            status += QString("%1 ").arg(fanInGates[i]->gateID);
            if (inputValues[i] == logicValue_0) status += "(0/";
            else if (inputValues[i] == logicValue_1) status += "(1/";
            else status += "(X/";
            if (inputFaultyValues[i] == logicValue_0) status += "0) ";
            else if (inputFaultyValues[i] == logicValue_1) status += "1) ";
            else status += "X) ";
        }
    if (fanOutGates.size() != 0) {
        status += "| Output Gates: ";
        for (int i = 0; i < fanOutGates.size(); i++)
            status += QString("%1 ").arg(fanOutGates[i]->gateID);
        if (outputValue == logicValue_0) status += "(0/";
        else if (outputValue == logicValue_1) status += "(1/";
        else status += "(X/";
        if (outputFaultyValue == logicValue_0) status += "0) ";
        else if (outputFaultyValue == logicValue_1) status += "1) ";
        else status += "X) ";
    }
    emit updateStatus(status);

    // On gate selection, highlight the input and output gates/wires
    setZValue(1);
    setHighlight(true, QColor(COLOR_MAIN_SELECTED));
    for (int i = 0; i < fanInGates.size(); i++)
        fanInGates[i]->setHighlight(true, QColor(COLOR_INPUT_SELECTED));
    for (int i = 0; i < fanOutGates.size(); i++)
        fanOutGates[i]->setHighlight(true, QColor(COLOR_OUTPUT_SELECTED));
    for (int i = 0; i < gateInputWires.size(); i++)
        gateInputWires[i]->setHighlight(true, QColor(COLOR_INPUT_SELECTED));
    for (int i = 0; i < gateOutputWires.size(); i++)
        gateOutputWires[i]->setHighlight(true, QColor(COLOR_OUTPUT_SELECTED));
    event->accept();
}

/*
void Gate_BASE::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{
    QMenu menu;
    menu.addAction(injectValueAction);
    menu.exec(event->screenPos());
    event->accept();
}

void Gate_BASE::createActions()
{
    injectValueAction = new QAction("&Inject Value/Fault", this);
}
*/