| 335 |
Kevin |
1 |
#include "Wire.h"
|
|
|
2 |
|
|
|
3 |
Wire::Wire(QGraphicsItem *parent) :
|
|
|
4 |
QGraphicsObject(parent)
|
|
|
5 |
{
|
|
|
6 |
setFlags(ItemIsSelectable);
|
|
|
7 |
|
|
|
8 |
createActions();
|
|
|
9 |
|
|
|
10 |
this->auxSelected = false;
|
|
|
11 |
this->showValues = true;
|
|
|
12 |
|
|
|
13 |
// Create the default pens to draw with
|
|
|
14 |
this->defaultPen = QPen(QColor(COLOR_MAIN), DEFAULT_LINE_WIDTH, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
|
|
|
15 |
this->defaultBrush = QBrush(Qt::NoBrush);
|
|
|
16 |
this->selectedPen = QPen(QColor(COLOR_MAIN_SELECTED), DEFAULT_LINE_WIDTH, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
|
|
|
17 |
this->highlightedPen = QPen(QColor(COLOR_MAIN_SELECTED), DEFAULT_LINE_WIDTH, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
|
|
|
18 |
this->defaultFont = QFont("Consolas", 20);
|
|
|
19 |
|
|
|
20 |
this->wireValue = logicValue_X;
|
|
|
21 |
this->wireFaultyValue = logicValue_X;
|
|
|
22 |
this->valueString = "X/X";
|
|
|
23 |
|
|
|
24 |
#ifdef _DEBUG
|
|
|
25 |
this->debugPen = QPen(QColor(COLOR_DEBUG), 1, Qt::DashLine);
|
|
|
26 |
this->debugBrush = QBrush(Qt::NoBrush);
|
|
|
27 |
this->debugSelectedPen = QPen(QColor(COLOR_DEBUG_SELECTED), 1, Qt::DashLine);
|
|
|
28 |
this->debugErrorPen = QPen(QColor(COLOR_DEBUG_ERROR), 2, Qt::DashLine);
|
|
|
29 |
#endif
|
|
|
30 |
}
|
|
|
31 |
|
|
|
32 |
Wire::~Wire()
|
|
|
33 |
{
|
|
|
34 |
|
|
|
35 |
}
|
|
|
36 |
|
|
|
37 |
QRectF Wire::boundingRect() const
|
|
|
38 |
{
|
|
|
39 |
QMargins margin(SELECTION_WIDTH, SELECTION_WIDTH, SELECTION_WIDTH, SELECTION_WIDTH);
|
|
|
40 |
return bRect + margin;
|
|
|
41 |
}
|
|
|
42 |
|
|
|
43 |
QPainterPath Wire::shape() const
|
|
|
44 |
{
|
|
|
45 |
return shapeArea;
|
|
|
46 |
}
|
|
|
47 |
|
|
|
48 |
void Wire::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
|
|
|
49 |
{
|
|
|
50 |
Q_UNUSED(widget);
|
|
|
51 |
Q_UNUSED(option);
|
|
|
52 |
|
|
|
53 |
#ifdef _DEBUG
|
|
|
54 |
painter->save();
|
|
|
55 |
painter->setPen((auxSelected) ? debugSelectedPen : debugPen);
|
|
|
56 |
painter->setBrush(debugBrush);
|
|
|
57 |
painter->drawRect(this->boundingRect());
|
|
|
58 |
painter->drawPath(shapeArea);
|
|
|
59 |
painter->restore();
|
|
|
60 |
#endif
|
|
|
61 |
|
|
|
62 |
// Set line color accordingly
|
|
|
63 |
if (auxSelected) painter->setPen(highlightedPen);
|
|
|
64 |
else painter->setPen(defaultPen);
|
|
|
65 |
painter->setBrush(defaultBrush);
|
|
|
66 |
|
|
|
67 |
// Draw the line
|
|
|
68 |
painter->drawPath(line);
|
|
|
69 |
|
|
|
70 |
QPainterPath textBox;
|
|
|
71 |
textBox.addText(0, 0, defaultFont, valueString);
|
|
|
72 |
|
|
|
73 |
// Draw the text (wire value)
|
|
|
74 |
if (showValues) {
|
|
|
75 |
QPainterPath text;
|
|
|
76 |
text.addText(bRect.center().x() - (textBox.boundingRect().width() / 2),
|
|
|
77 |
bRect.center().y() + (textBox.boundingRect().height() / 2) - 2,
|
|
|
78 |
defaultFont, valueString);
|
|
|
79 |
|
|
|
80 |
QPainterPathStroker stroker;
|
|
|
81 |
stroker.setCapStyle(Qt::RoundCap);
|
|
|
82 |
stroker.setJoinStyle(Qt::RoundJoin);
|
|
|
83 |
stroker.setWidth(10);
|
|
|
84 |
QPainterPath textOutline = stroker.createStroke(text);
|
|
|
85 |
painter->save();
|
|
|
86 |
painter->setPen(QPen(Qt::white));
|
|
|
87 |
painter->setBrush(QBrush(Qt::white));
|
|
|
88 |
painter->drawPath(textOutline);
|
|
|
89 |
painter->restore();
|
|
|
90 |
|
|
|
91 |
painter->drawPath(text);
|
|
|
92 |
}
|
|
|
93 |
}
|
|
|
94 |
|
|
|
95 |
/**
|
|
|
96 |
* Draw line from given point to point
|
|
|
97 |
*/
|
|
|
98 |
void Wire::setPoints(Gate_BASE *source, Gate_BASE *sink, int sinkID)
|
|
|
99 |
{
|
|
|
100 |
this->gateOutput = source;
|
|
|
101 |
this->gateInput = sink;
|
|
|
102 |
this->gateInputID = sinkID;
|
|
|
103 |
|
|
|
104 |
// Calculate the bounding box of this line (normalized)
|
|
|
105 |
bRect = QRectF(gateOutput->gateOutputPoint, gateInput->gateInputPoints[gateInputID]).normalized();
|
|
|
106 |
|
|
|
107 |
// Move box to center of object
|
|
|
108 |
QPointF center = bRect.center();
|
|
|
109 |
bRect.translate(- center.x(), - center.y());
|
|
|
110 |
|
|
|
111 |
// Calculate new I/O points in local coordinates
|
|
|
112 |
QPointF tOutput = gateOutput->gateOutputPoint - center;
|
|
|
113 |
QPointF tInput = gateInput->gateInputPoints[gateInputID] - center;
|
|
|
114 |
|
|
|
115 |
// Draw the line
|
|
|
116 |
linePoints.append(tOutput);
|
|
|
117 |
linePoints.append(QPointF(bRect.center().x(), tOutput.y()));
|
|
|
118 |
linePoints.append(QPointF(bRect.center().x(), tInput.y()));
|
|
|
119 |
linePoints.append(tInput);
|
|
|
120 |
line.moveTo(linePoints[0]);
|
|
|
121 |
for (int i = 1; i < linePoints.size(); i++) {
|
|
|
122 |
line.lineTo(linePoints[i]);
|
|
|
123 |
}
|
|
|
124 |
|
|
|
125 |
// Stroke the line to allow for selection
|
|
|
126 |
QPainterPathStroker stroke;
|
|
|
127 |
stroke.setWidth(SELECTION_WIDTH);
|
|
|
128 |
shapeArea = stroke.createStroke(line);
|
|
|
129 |
|
|
|
130 |
// Move wire on canvas to proper location
|
|
|
131 |
this->setPos(center.x(), center.y());
|
|
|
132 |
prepareGeometryChange();
|
|
|
133 |
}
|
|
|
134 |
|
|
|
135 |
/**
|
|
|
136 |
* Sets the color of the pen drawing the line
|
|
|
137 |
*/
|
|
|
138 |
void Wire::setPenColor(QColor color)
|
|
|
139 |
{
|
|
|
140 |
this->defaultPen.setColor(color);
|
|
|
141 |
}
|
|
|
142 |
|
|
|
143 |
/**
|
|
|
144 |
* Sets the highlight color when wire is selected
|
|
|
145 |
*/
|
|
|
146 |
void Wire::setHighlight(bool state, QColor color)
|
|
|
147 |
{
|
|
|
148 |
auxSelected = state;
|
|
|
149 |
if (state) {
|
|
|
150 |
highlightedPen.setColor(color);
|
|
|
151 |
setZValue(SELECTED_Z);
|
|
|
152 |
} else {
|
|
|
153 |
setZValue(WIRE_DEFAULT_Z);
|
|
|
154 |
}
|
|
|
155 |
update();
|
|
|
156 |
}
|
|
|
157 |
|
|
|
158 |
/**
|
|
|
159 |
* Resets the value of the wire to unknown 'X'
|
|
|
160 |
*/
|
|
|
161 |
void Wire::reset()
|
|
|
162 |
{
|
|
|
163 |
setValue(logicValue_X, logicValue_X);
|
|
|
164 |
update();
|
|
|
165 |
}
|
|
|
166 |
|
|
|
167 |
/**
|
|
|
168 |
* Toggles if wire values should be shown
|
|
|
169 |
*/
|
|
|
170 |
void Wire::toggleShowValues()
|
|
|
171 |
{
|
|
|
172 |
showValues = !showValues;
|
|
|
173 |
update();
|
|
|
174 |
}
|
|
|
175 |
|
|
|
176 |
/**
|
|
|
177 |
* Sets the value of the wire
|
|
|
178 |
*/
|
|
|
179 |
void Wire::setValue(logicValue value, logicValue faultyValue, bool recurse)
|
|
|
180 |
{
|
|
|
181 |
wireValue = value;
|
|
|
182 |
wireFaultyValue = faultyValue;
|
|
|
183 |
|
|
|
184 |
// Compute the status string
|
|
|
185 |
valueString = "";
|
|
|
186 |
if (wireValue == logicValue_0) valueString += "0";
|
|
|
187 |
else if (wireValue == logicValue_1) valueString += "1";
|
|
|
188 |
else valueString += "X";
|
|
|
189 |
valueString += "/";
|
|
|
190 |
if (wireFaultyValue == logicValue_0) valueString += "0";
|
|
|
191 |
else if (wireFaultyValue == logicValue_1) valueString += "1";
|
|
|
192 |
else valueString += "X";
|
|
|
193 |
|
|
|
194 |
// Propogate value to sink/source gates
|
|
|
195 |
gateInput->setInputValue(gateInputID, wireValue, wireFaultyValue);
|
|
|
196 |
gateInput->setOutputValue(wireValue, wireFaultyValue);
|
|
|
197 |
|
|
|
198 |
// Propogate to gates if necessary
|
|
|
199 |
if (recurse) {
|
|
|
200 |
for (int i = 0; i < gateOutput->gateOutputWires.size(); i++) {
|
|
|
201 |
gateOutput->gateOutputWires[i]->setValue(wireValue, wireFaultyValue, false);
|
|
|
202 |
}
|
|
|
203 |
}
|
|
|
204 |
|
|
|
205 |
update();
|
|
|
206 |
}
|
|
|
207 |
|
|
|
208 |
void Wire::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
|
|
209 |
{
|
|
|
210 |
QString status = QString("Wire Source: Gate %1 | Sink: Gate %2 | Value: ").arg(gateOutput->gateID).arg(gateInput->gateID);
|
|
|
211 |
status += valueString;
|
|
|
212 |
emit updateStatus(status);
|
|
|
213 |
|
|
|
214 |
// On selection, highlight sink and source gates
|
|
|
215 |
setZValue(1);
|
|
|
216 |
setHighlight(true, QColor(COLOR_MAIN_SELECTED));
|
|
|
217 |
gateOutput->setHighlight(true, QColor(COLOR_OUTPUT_SELECTED));
|
|
|
218 |
gateInput->setHighlight(true, QColor(COLOR_INPUT_SELECTED));
|
|
|
219 |
event->accept();
|
|
|
220 |
}
|
|
|
221 |
|
|
|
222 |
void Wire::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
|
|
|
223 |
{
|
|
|
224 |
QMenu menu;
|
|
|
225 |
menu.addAction(injectValueAction);
|
|
|
226 |
menu.addAction(injectFaultAction);
|
|
|
227 |
menu.addAction(resetValuesAction);
|
|
|
228 |
menu.exec(event->screenPos());
|
|
|
229 |
event->accept();
|
|
|
230 |
}
|
|
|
231 |
|
|
|
232 |
void Wire::createActions()
|
|
|
233 |
{
|
|
|
234 |
injectValueAction = new QAction("&Set Value", this);
|
|
|
235 |
connect(injectValueAction, SIGNAL(triggered()), this, SLOT(promptValue()));
|
|
|
236 |
|
|
|
237 |
injectFaultAction = new QAction("&Inject Fault", this);
|
|
|
238 |
connect(injectFaultAction, SIGNAL(triggered()), this, SLOT(promptFaultyValue()));
|
|
|
239 |
|
|
|
240 |
resetValuesAction = new QAction("&Reset Values", this);
|
|
|
241 |
connect(resetValuesAction, SIGNAL(triggered()), this, SLOT(reset()));
|
|
|
242 |
}
|
|
|
243 |
|
|
|
244 |
void Wire::promptValue()
|
|
|
245 |
{
|
|
|
246 |
bool ok;
|
|
|
247 |
QStringList options;
|
|
|
248 |
options << "0" << "1";
|
|
|
249 |
QString sel = QInputDialog::getItem(0, "Choose Value", "Enter Value:", options, 0, false, &ok);
|
|
|
250 |
if (ok && !sel.isEmpty()) {
|
|
|
251 |
if (sel == "0") setValue(logicValue_0, logicValue_0);
|
|
|
252 |
else if (sel == "1") setValue(logicValue_1, logicValue_1);
|
|
|
253 |
else setValue(logicValue_X, logicValue_X);
|
|
|
254 |
}
|
|
|
255 |
}
|
|
|
256 |
|
|
|
257 |
void Wire::promptFaultyValue()
|
|
|
258 |
{
|
|
|
259 |
bool ok;
|
|
|
260 |
QStringList options;
|
|
|
261 |
options << "0" << "1";
|
|
|
262 |
QString sel = QInputDialog::getItem(0, "Choose Value", "Enter Faulty Value:", options, 0, false, &ok);
|
|
|
263 |
if (ok && !sel.isEmpty()) {
|
|
|
264 |
if (sel == "0") setValue(logicValue_1, logicValue_0);
|
|
|
265 |
else if (sel == "1") setValue(logicValue_0, logicValue_1);
|
|
|
266 |
else setValue(logicValue_X, logicValue_X);
|
|
|
267 |
}
|
|
|
268 |
}
|