0,0 → 1,305 |
#include "Canvas.h" |
|
Canvas::Canvas(QWidget *parent) : QGraphicsView(parent) |
{ |
// Set some drawing options to improve performance |
setBackgroundRole(QPalette::Base); |
setAutoFillBackground(true); |
setFrameStyle(Sunken | StyledPanel); |
setRenderHint(QPainter::Antialiasing, true); |
setDragMode(QGraphicsView::RubberBandDrag); |
setOptimizationFlags(QGraphicsView::DontSavePainterState); |
setViewportUpdateMode(QGraphicsView::SmartViewportUpdate); |
setTransformationAnchor(QGraphicsView::AnchorUnderMouse); |
|
scene = new QGraphicsScene; |
setScene(scene); |
|
zoomLevel = 100; |
_pan = false; |
|
circuit = NULL; |
|
// Draw axis lines when running in debug mode |
#ifdef _DEBUG |
QGraphicsLineItem *xAxis = new QGraphicsLineItem(-1000, 0, 1000, 0); |
QGraphicsLineItem *yAxis = new QGraphicsLineItem(0, -800, 0, 800); |
scene->addItem(xAxis); |
scene->addItem(yAxis); |
debugPen = QPen(QColor(COLOR_WIRE_REGION_OUTLINE), 1, Qt::DashDotLine); |
#endif |
|
/* |
Gate_BASE *g; |
for (int i = 1; i < 6; i++) { |
g = new Gate_INPUT(0, gate_INPUT, i, 0); |
scene->addItem(g); |
g->setCanvasPosition(BASE_GATE_SIZE_X + i * 2 * (BASE_GATE_SIZE_X + 20), 000); |
|
g = new Gate_OUTPUT(0, gate_INPUT, i, 0); |
scene->addItem(g); |
g->setCanvasPosition(BASE_GATE_SIZE_X + i * 2 * (BASE_GATE_SIZE_X + 20), 150); |
|
g = new Gate_BUFFER(0, gate_INPUT, i, 0); |
scene->addItem(g); |
g->setCanvasPosition(BASE_GATE_SIZE_X + i * 2 * (BASE_GATE_SIZE_X + 20), 300); |
|
g = new Gate_AND(0, gate_INPUT, i, 0); |
scene->addItem(g); |
g->setCanvasPosition(BASE_GATE_SIZE_X + i * 2 * (BASE_GATE_SIZE_X + 20), 500); |
|
g = new Gate_NAND(0, gate_INPUT, i, 0); |
scene->addItem(g); |
g->setCanvasPosition(BASE_GATE_SIZE_X + i * 2 * (BASE_GATE_SIZE_X + 20), 700); |
|
g = new Gate_OR(0, gate_INPUT, i, 0); |
scene->addItem(g); |
g->setCanvasPosition(BASE_GATE_SIZE_X + i * 2 * (BASE_GATE_SIZE_X + 20), 900); |
|
g = new Gate_NOR(0, gate_INPUT, i, 0); |
scene->addItem(g); |
g->setCanvasPosition(BASE_GATE_SIZE_X + i * 2 * (BASE_GATE_SIZE_X + 20), 1100); |
|
g = new Gate_XOR(0, gate_INPUT, i, 0); |
scene->addItem(g); |
g->setCanvasPosition(BASE_GATE_SIZE_X + i * 2 * (BASE_GATE_SIZE_X + 20), 1300); |
|
g = new Gate_XNOR(0, gate_INPUT, i, 0); |
scene->addItem(g); |
g->setCanvasPosition(BASE_GATE_SIZE_X + i * 2 * (BASE_GATE_SIZE_X + 20), 1500); |
|
g = new Gate_NOT(0, gate_INPUT, i, 0); |
scene->addItem(g); |
g->setCanvasPosition(BASE_GATE_SIZE_X + i * 2 * (BASE_GATE_SIZE_X + 20), 1700); |
|
g = new Gate_DFF(0, gate_INPUT, i, 0); |
scene->addItem(g); |
g->setCanvasPosition(BASE_GATE_SIZE_X + i * 2 * (BASE_GATE_SIZE_X + 20), 1900); |
}*/ |
|
} |
|
QSize Canvas::minimumSizeHint() const |
{ |
return QSize(400,400); |
} |
|
QSize Canvas::sizeHint() const |
{ |
return QSize(800,600); |
} |
|
void Canvas::drawCircuit(Circuit *circuit) |
{ |
|
this->circuit = circuit; |
|
// Calculate the maximum distance between gates including spacing |
int largestLevelCount = 0; int largestYSize = 0; |
for (int i = 0; i < circuit->gatesPerLevel.keys().size(); i++) { |
int level = circuit->gatesPerLevel.keys()[i]; |
QList<Gate_BASE*> gates = circuit->gatesPerLevel[level]; |
|
// We want center to center distance of top and bottom gate |
int levelYSize = (gates[0]->ySize / 2) + (gates[gates.size() - 1]->ySize / 2); |
levelYSize += CANVAS_GATE_Y_SPACING * (gates.size() - 1); |
for (int j = 1; j < gates.size() - 1; j++) { |
levelYSize += gates[j]->ySize; |
} |
if (levelYSize > largestYSize) { |
largestLevelCount = gates.size(); |
largestYSize = levelYSize; |
} |
} |
|
|
// Iterate through each level of the circuit and draw the gates |
int xOffset = 0, yOffset = 0, ySpacing = 0; |
int xSize = (circuit->gatesPerLevel.keys().size() - 1) * CANVAS_GATE_X_SPACING; |
xOffset = - xSize / 2; |
for (int i = 0; i < circuit->gatesPerLevel.keys().size(); i++) { |
int level = circuit->gatesPerLevel.keys()[i]; |
QList<Gate_BASE*> gates = circuit->gatesPerLevel[level]; |
|
// Calculate offsets and spacing between gates |
if (gates.size() == largestLevelCount) { |
ySpacing = largestYSize / (gates.size() - 1); |
yOffset = - largestYSize / 2; |
} else { |
ySpacing = largestYSize / (gates.size()); |
yOffset = - largestYSize / 2 + ySpacing / 2; |
} |
|
// Draw gates onto canvas |
for (int j = 0; j < gates.size(); j++) { |
scene->addItem(gates[j]); |
connect(gates[j], SIGNAL(updateStatus(QString)), this, SIGNAL(updateStatus(QString))); |
gates[j]->setCanvasPosition(xOffset, yOffset); |
yOffset += ySpacing; |
} |
|
xOffset += CANVAS_GATE_X_SPACING; |
} |
|
/* |
// Go through and calculate wiring region between gate objects |
wireSpace *vSpacing; |
for (int i = 1; i < circuit->gatesPerLevel.keys().size() - 1; i++) { |
int level = circuit->gatesPerLevel.keys()[i]; |
QList<Gate_BASE*> gates = circuit->gatesPerLevel[level]; |
|
// Compute and save top region |
QRectF topSpace = QRectF(gates[0]->x(), -largestYSize / 2, gates[0]->xSize, gates[0]->y() + largestYSize / 2); |
vSpacing = new wireSpace; |
vSpacing->region = topSpace; |
circuit->wireVSpacing[level].append(vSpacing); |
|
// Compute and save intermediate regions |
for (int j = 0; j < gates.size() - 1; j++) { |
QRectF midSpace; |
if (gates[j]->xSize >= gates[j+1]->xSize) { |
midSpace = QRectF(gates[j]->x(), gates[j]->y() + gates[j]->ySize, gates[j]->xSize, gates[j+1]->y() - (gates[j]->y() + gates[j]->ySize)); |
} else { |
midSpace = QRectF(gates[j+1]->x(), gates[j]->y() + gates[j]->ySize, gates[j+1]->xSize, gates[j+1]->y() - (gates[j]->y() + gates[j]->ySize)); |
} |
|
vSpacing = new wireSpace; |
vSpacing->region = midSpace; |
circuit->wireVSpacing[level].append(vSpacing); |
} |
|
// Compute and save bottom region |
Gate_BASE *lastGate = gates[gates.size() - 1]; |
QRectF botSpace = QRectF(lastGate->x(), lastGate->y() + lastGate->ySize, lastGate->xSize, largestYSize / 2 - (lastGate->y() + lastGate->ySize)); |
vSpacing = new wireSpace; |
vSpacing->region = botSpace; |
circuit->wireVSpacing[level].append(vSpacing); |
|
// Draw regions in debug mode |
#ifdef _DEBUG |
for (int j = 0; j < circuit->wireVSpacing[level].size(); j++) |
scene->addRect(circuit->wireVSpacing[level][j]->region, debugPen, QBrush(QColor(COLOR_WIRE_REGION_V))); |
#endif |
}*/ |
|
/* |
// Go through and calculate wiring region between levels |
wireSpace *hSpacing; |
for (int i = 0; i < circuit->gatesPerLevel.keys().size() - 1; i++) { |
int level = circuit->gatesPerLevel.keys()[i]; |
QList<Gate_BASE*> gates = circuit->gatesPerLevel[level]; |
|
// Compute the max X position for this level and min X position for next level |
|
}*/ |
|
|
// Instantiate wires for each output->input connection on each gate |
QList<int> gateIDs = circuit->gateIndex.keys(); |
for (int i = 0; i < gateIDs.size(); i++) { |
Gate_BASE *tmp = circuit->gateIndex[gateIDs[i]]; |
// Connect each gate's input to other gate's output |
for (int j = 0; j < tmp->fanInGates.size(); j++) { |
Wire *wire = new Wire(); |
wire->setPoints(tmp->fanInGates[j], tmp, j); |
// Store wires in gates on both ends |
tmp->gateInputWires.append(wire); |
tmp->fanInGates[j]->gateOutputWires.append(wire); |
// Save wire information into circuit |
circuit->wires.append(wire); |
connect(wire, SIGNAL(updateStatus(QString)), this, SIGNAL(updateStatus(QString))); |
connect(circuit, SIGNAL(toggleShowWireValues()), wire, SLOT(toggleShowValues())); |
scene->addItem(wire); |
} |
} |
|
scene->update(); |
emit updateStatus("Circuit file successfully loaded"); |
} |
|
/** |
* Zooms the canvas using matrix scaling |
*/ |
void Canvas::zoomCanvas(int level) |
{ |
zoomLevel = level; |
|
qreal scale = qPow(qreal(2), (zoomLevel - 160) / qreal(40)); |
|
QMatrix matrix; |
matrix.scale(scale,scale); |
|
setMatrix(matrix); |
} |
|
#ifndef QT_NO_WHEELEVENT |
void Canvas::wheelEvent(QWheelEvent *event) |
{ |
// Zoom canvas on scroll wheel |
if (event->delta() > 0) { |
zoomCanvas(zoomLevel + 5); |
emit updateZoomSlider(zoomLevel + 5); |
} else { |
zoomCanvas(zoomLevel - 5); |
emit updateZoomSlider(zoomLevel - 5); |
} |
event->accept(); |
} |
#endif |
|
void Canvas::mousePressEvent(QMouseEvent *event) |
{ |
// If CTRL is held down, pan the canvas |
if (event->modifiers() & Qt::ControlModifier) { |
_pan = true; |
_panStartX = event->x(); |
_panStartY = event->y(); |
setCursor(Qt::ClosedHandCursor); |
event->accept(); |
return; |
} |
|
if (circuit != NULL && circuit->circuitLoaded) { |
// Clear any previously selected gates and wires |
for (int i = 0; i < circuit->gatesPerLevel.size(); i++) { |
QList<Gate_BASE*> gates = circuit->gatesPerLevel[i]; |
for (int j = 0; j < gates.size(); j++) { |
gates[j]->setHighlight(false, QColor(0,0,0,255)); |
} |
} |
for (int i = 0; i < circuit->wires.size(); i++) { |
circuit->wires[i]->setHighlight(false, QColor(0,0,0,255)); |
} |
updateStatus(""); |
} |
|
// If not panning, propogate event to child objects |
QGraphicsView::mousePressEvent(event); |
} |
|
void Canvas::mouseMoveEvent(QMouseEvent *event) |
{ |
// Process panning if active |
if (_pan) { |
horizontalScrollBar()->setValue(horizontalScrollBar()->value() - (event->x() - _panStartX)); |
verticalScrollBar()->setValue(verticalScrollBar()->value() - (event->y() - _panStartY)); |
_panStartX = event->x(); |
_panStartY = event->y(); |
event->accept(); |
return; |
} |
|
// Otherwise propogate event to child objects |
QGraphicsView::mouseMoveEvent(event); |
} |
|
void Canvas::mouseReleaseEvent(QMouseEvent *event) |
{ |
// Stop panning if active |
_pan = false; |
setCursor(Qt::ArrowCursor); |
event->accept(); |
|
// Propogate event to child objects |
QGraphicsView::mouseReleaseEvent(event); |
} |