Blame | Last modification | View Log | RSS feed
#include "Wire.h"
Wire::Wire(QGraphicsItem *parent) :
QGraphicsObject(parent)
{
setFlags(ItemIsSelectable);
createActions();
this->auxSelected = false;
this->showValues = true;
// 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->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);
this->defaultFont = QFont("Consolas", 20);
this->wireValue = logicValue_X;
this->wireFaultyValue = logicValue_X;
this->valueString = "X/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
}
Wire::~Wire()
{
}
QRectF Wire::boundingRect() const
{
QMargins margin(SELECTION_WIDTH, SELECTION_WIDTH, SELECTION_WIDTH, SELECTION_WIDTH);
return bRect + margin;
}
QPainterPath Wire::shape() const
{
return shapeArea;
}
void Wire::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(widget);
Q_UNUSED(option);
#ifdef _DEBUG
painter->save();
painter->setPen((auxSelected) ? debugSelectedPen : debugPen);
painter->setBrush(debugBrush);
painter->drawRect(this->boundingRect());
painter->drawPath(shapeArea);
painter->restore();
#endif
// Set line color accordingly
if (auxSelected) painter->setPen(highlightedPen);
else painter->setPen(defaultPen);
painter->setBrush(defaultBrush);
// Draw the line
painter->drawPath(line);
QPainterPath textBox;
textBox.addText(0, 0, defaultFont, valueString);
// Draw the text (wire value)
if (showValues) {
QPainterPath text;
text.addText(bRect.center().x() - (textBox.boundingRect().width() / 2),
bRect.center().y() + (textBox.boundingRect().height() / 2) - 2,
defaultFont, valueString);
QPainterPathStroker stroker;
stroker.setCapStyle(Qt::RoundCap);
stroker.setJoinStyle(Qt::RoundJoin);
stroker.setWidth(10);
QPainterPath textOutline = stroker.createStroke(text);
painter->save();
painter->setPen(QPen(Qt::white));
painter->setBrush(QBrush(Qt::white));
painter->drawPath(textOutline);
painter->restore();
painter->drawPath(text);
}
}
/**
* Draw line from given point to point
*/
void Wire::setPoints(Gate_BASE *source, Gate_BASE *sink, int sinkID)
{
this->gateOutput = source;
this->gateInput = sink;
this->gateInputID = sinkID;
// Calculate the bounding box of this line (normalized)
bRect = QRectF(gateOutput->gateOutputPoint, gateInput->gateInputPoints[gateInputID]).normalized();
// Move box to center of object
QPointF center = bRect.center();
bRect.translate(- center.x(), - center.y());
// Calculate new I/O points in local coordinates
QPointF tOutput = gateOutput->gateOutputPoint - center;
QPointF tInput = gateInput->gateInputPoints[gateInputID] - center;
// Draw the line
linePoints.append(tOutput);
linePoints.append(QPointF(bRect.center().x(), tOutput.y()));
linePoints.append(QPointF(bRect.center().x(), tInput.y()));
linePoints.append(tInput);
line.moveTo(linePoints[0]);
for (int i = 1; i < linePoints.size(); i++) {
line.lineTo(linePoints[i]);
}
// Stroke the line to allow for selection
QPainterPathStroker stroke;
stroke.setWidth(SELECTION_WIDTH);
shapeArea = stroke.createStroke(line);
// Move wire on canvas to proper location
this->setPos(center.x(), center.y());
prepareGeometryChange();
}
/**
* Sets the color of the pen drawing the line
*/
void Wire::setPenColor(QColor color)
{
this->defaultPen.setColor(color);
}
/**
* Sets the highlight color when wire is selected
*/
void Wire::setHighlight(bool state, QColor color)
{
auxSelected = state;
if (state) {
highlightedPen.setColor(color);
setZValue(SELECTED_Z);
} else {
setZValue(WIRE_DEFAULT_Z);
}
update();
}
/**
* Resets the value of the wire to unknown 'X'
*/
void Wire::reset()
{
setValue(logicValue_X, logicValue_X);
update();
}
/**
* Toggles if wire values should be shown
*/
void Wire::toggleShowValues()
{
showValues = !showValues;
update();
}
/**
* Sets the value of the wire
*/
void Wire::setValue(logicValue value, logicValue faultyValue, bool recurse)
{
wireValue = value;
wireFaultyValue = faultyValue;
// Compute the status string
valueString = "";
if (wireValue == logicValue_0) valueString += "0";
else if (wireValue == logicValue_1) valueString += "1";
else valueString += "X";
valueString += "/";
if (wireFaultyValue == logicValue_0) valueString += "0";
else if (wireFaultyValue == logicValue_1) valueString += "1";
else valueString += "X";
// Propogate value to sink/source gates
gateInput->setInputValue(gateInputID, wireValue, wireFaultyValue);
gateInput->setOutputValue(wireValue, wireFaultyValue);
// Propogate to gates if necessary
if (recurse) {
for (int i = 0; i < gateOutput->gateOutputWires.size(); i++) {
gateOutput->gateOutputWires[i]->setValue(wireValue, wireFaultyValue, false);
}
}
update();
}
void Wire::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
QString status = QString("Wire Source: Gate %1 | Sink: Gate %2 | Value: ").arg(gateOutput->gateID).arg(gateInput->gateID);
status += valueString;
emit updateStatus(status);
// On selection, highlight sink and source gates
setZValue(1);
setHighlight(true, QColor(COLOR_MAIN_SELECTED));
gateOutput->setHighlight(true, QColor(COLOR_OUTPUT_SELECTED));
gateInput->setHighlight(true, QColor(COLOR_INPUT_SELECTED));
event->accept();
}
void Wire::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{
QMenu menu;
menu.addAction(injectValueAction);
menu.addAction(injectFaultAction);
menu.addAction(resetValuesAction);
menu.exec(event->screenPos());
event->accept();
}
void Wire::createActions()
{
injectValueAction = new QAction("&Set Value", this);
connect(injectValueAction, SIGNAL(triggered()), this, SLOT(promptValue()));
injectFaultAction = new QAction("&Inject Fault", this);
connect(injectFaultAction, SIGNAL(triggered()), this, SLOT(promptFaultyValue()));
resetValuesAction = new QAction("&Reset Values", this);
connect(resetValuesAction, SIGNAL(triggered()), this, SLOT(reset()));
}
void Wire::promptValue()
{
bool ok;
QStringList options;
options << "0" << "1";
QString sel = QInputDialog::getItem(0, "Choose Value", "Enter Value:", options, 0, false, &ok);
if (ok && !sel.isEmpty()) {
if (sel == "0") setValue(logicValue_0, logicValue_0);
else if (sel == "1") setValue(logicValue_1, logicValue_1);
else setValue(logicValue_X, logicValue_X);
}
}
void Wire::promptFaultyValue()
{
bool ok;
QStringList options;
options << "0" << "1";
QString sel = QInputDialog::getItem(0, "Choose Value", "Enter Faulty Value:", options, 0, false, &ok);
if (ok && !sel.isEmpty()) {
if (sel == "0") setValue(logicValue_1, logicValue_0);
else if (sel == "1") setValue(logicValue_0, logicValue_1);
else setValue(logicValue_X, logicValue_X);
}
}