Blame | Last modification | View Log | Download | RSS feed
#include "Canvas.h"Canvas::Canvas(QWidget *parent) : QGraphicsView(parent){// Set some drawing options to improve performancesetBackgroundRole(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 _DEBUGQGraphicsLineItem *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 spacingint 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 gateint 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 gatesint 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 gatesif (gates.size() == largestLevelCount) {ySpacing = largestYSize / (gates.size() - 1);yOffset = - largestYSize / 2;} else {ySpacing = largestYSize / (gates.size());yOffset = - largestYSize / 2 + ySpacing / 2;}// Draw gates onto canvasfor (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 objectswireSpace *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 regionQRectF 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 regionsfor (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 regionGate_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 _DEBUGfor (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 levelswireSpace *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 gateQList<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 outputfor (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 endstmp->gateInputWires.append(wire);tmp->fanInGates[j]->gateOutputWires.append(wire);// Save wire information into circuitcircuit->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_WHEELEVENTvoid Canvas::wheelEvent(QWheelEvent *event){// Zoom canvas on scroll wheelif (event->delta() > 0) {zoomCanvas(zoomLevel + 5);emit updateZoomSlider(zoomLevel + 5);} else {zoomCanvas(zoomLevel - 5);emit updateZoomSlider(zoomLevel - 5);}event->accept();}#endifvoid Canvas::mousePressEvent(QMouseEvent *event){// If CTRL is held down, pan the canvasif (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 wiresfor (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 objectsQGraphicsView::mousePressEvent(event);}void Canvas::mouseMoveEvent(QMouseEvent *event){// Process panning if activeif (_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 objectsQGraphicsView::mouseMoveEvent(event);}void Canvas::mouseReleaseEvent(QMouseEvent *event){// Stop panning if active_pan = false;setCursor(Qt::ArrowCursor);event->accept();// Propogate event to child objectsQGraphicsView::mouseReleaseEvent(event);}