0,0 → 1,268 |
#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); |
} |
} |