Subversion Repositories Code-Repo

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
335 Kevin 1
#include "Canvas.h"
2
 
3
Canvas::Canvas(QWidget *parent) : QGraphicsView(parent)
4
{
5
    // Set some drawing options to improve performance
6
    setBackgroundRole(QPalette::Base);
7
    setAutoFillBackground(true);
8
    setFrameStyle(Sunken | StyledPanel);
9
    setRenderHint(QPainter::Antialiasing, true);
10
    setDragMode(QGraphicsView::RubberBandDrag);
11
    setOptimizationFlags(QGraphicsView::DontSavePainterState);
12
    setViewportUpdateMode(QGraphicsView::SmartViewportUpdate);
13
    setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
14
 
15
    scene = new QGraphicsScene;
16
    setScene(scene);
17
 
18
    zoomLevel = 100;
19
    _pan = false;
20
 
21
    circuit = NULL;
22
 
23
    // Draw axis lines when running in debug mode
24
#ifdef _DEBUG
25
    QGraphicsLineItem *xAxis = new QGraphicsLineItem(-1000, 0, 1000, 0);
26
    QGraphicsLineItem *yAxis = new QGraphicsLineItem(0, -800, 0, 800);
27
    scene->addItem(xAxis);
28
    scene->addItem(yAxis);
29
    debugPen = QPen(QColor(COLOR_WIRE_REGION_OUTLINE), 1, Qt::DashDotLine);
30
#endif
31
 
32
/*
33
    Gate_BASE *g;
34
    for (int i = 1; i < 6; i++) {
35
        g = new Gate_INPUT(0, gate_INPUT, i, 0);
36
        scene->addItem(g);
37
        g->setCanvasPosition(BASE_GATE_SIZE_X + i * 2 * (BASE_GATE_SIZE_X + 20), 000);
38
 
39
        g = new Gate_OUTPUT(0, gate_INPUT, i, 0);
40
        scene->addItem(g);
41
        g->setCanvasPosition(BASE_GATE_SIZE_X + i * 2 * (BASE_GATE_SIZE_X + 20), 150);
42
 
43
        g = new Gate_BUFFER(0, gate_INPUT, i, 0);
44
        scene->addItem(g);
45
        g->setCanvasPosition(BASE_GATE_SIZE_X + i * 2 * (BASE_GATE_SIZE_X + 20), 300);
46
 
47
        g = new Gate_AND(0, gate_INPUT, i, 0);
48
        scene->addItem(g);
49
        g->setCanvasPosition(BASE_GATE_SIZE_X + i * 2 * (BASE_GATE_SIZE_X + 20), 500);
50
 
51
        g = new Gate_NAND(0, gate_INPUT, i, 0);
52
        scene->addItem(g);
53
        g->setCanvasPosition(BASE_GATE_SIZE_X + i * 2 * (BASE_GATE_SIZE_X + 20), 700);
54
 
55
        g = new Gate_OR(0, gate_INPUT, i, 0);
56
        scene->addItem(g);
57
        g->setCanvasPosition(BASE_GATE_SIZE_X + i * 2 * (BASE_GATE_SIZE_X + 20), 900);
58
 
59
        g = new Gate_NOR(0, gate_INPUT, i, 0);
60
        scene->addItem(g);
61
        g->setCanvasPosition(BASE_GATE_SIZE_X + i * 2 * (BASE_GATE_SIZE_X + 20), 1100);
62
 
63
        g = new Gate_XOR(0, gate_INPUT, i, 0);
64
        scene->addItem(g);
65
        g->setCanvasPosition(BASE_GATE_SIZE_X + i * 2 * (BASE_GATE_SIZE_X + 20), 1300);
66
 
67
        g = new Gate_XNOR(0, gate_INPUT, i, 0);
68
        scene->addItem(g);
69
        g->setCanvasPosition(BASE_GATE_SIZE_X + i * 2 * (BASE_GATE_SIZE_X + 20), 1500);
70
 
71
        g = new Gate_NOT(0, gate_INPUT, i, 0);
72
        scene->addItem(g);
73
        g->setCanvasPosition(BASE_GATE_SIZE_X + i * 2 * (BASE_GATE_SIZE_X + 20), 1700);
74
 
75
        g = new Gate_DFF(0, gate_INPUT, i, 0);
76
        scene->addItem(g);
77
        g->setCanvasPosition(BASE_GATE_SIZE_X + i * 2 * (BASE_GATE_SIZE_X + 20), 1900);
78
    }*/
79
 
80
}
81
 
82
QSize Canvas::minimumSizeHint() const
83
{
84
    return QSize(400,400);
85
}
86
 
87
QSize Canvas::sizeHint() const
88
{
89
    return QSize(800,600);
90
}
91
 
92
void Canvas::drawCircuit(Circuit *circuit)
93
{
94
 
95
    this->circuit = circuit;
96
 
97
    // Calculate the maximum distance between gates including spacing
98
    int largestLevelCount = 0; int largestYSize = 0;
99
    for (int i = 0; i < circuit->gatesPerLevel.keys().size(); i++) {
100
        int level = circuit->gatesPerLevel.keys()[i];
101
        QList<Gate_BASE*> gates = circuit->gatesPerLevel[level];
102
 
103
        // We want center to center distance of top and bottom gate
104
        int levelYSize = (gates[0]->ySize / 2) + (gates[gates.size() - 1]->ySize / 2);
105
        levelYSize += CANVAS_GATE_Y_SPACING * (gates.size() - 1);
106
        for (int j = 1; j < gates.size() - 1; j++) {
107
            levelYSize += gates[j]->ySize;
108
        }
109
        if (levelYSize > largestYSize) {
110
            largestLevelCount = gates.size();
111
            largestYSize = levelYSize;
112
        }
113
    }
114
 
115
 
116
    // Iterate through each level of the circuit and draw the gates
117
    int xOffset = 0, yOffset = 0, ySpacing = 0;
118
    int xSize = (circuit->gatesPerLevel.keys().size() - 1) * CANVAS_GATE_X_SPACING;
119
    xOffset = - xSize / 2;
120
    for (int i = 0; i < circuit->gatesPerLevel.keys().size(); i++) {
121
        int level = circuit->gatesPerLevel.keys()[i];
122
        QList<Gate_BASE*> gates = circuit->gatesPerLevel[level];
123
 
124
        // Calculate offsets and spacing between gates
125
        if (gates.size() == largestLevelCount) {
126
            ySpacing = largestYSize / (gates.size() - 1);
127
            yOffset = - largestYSize / 2;
128
        } else {
129
            ySpacing = largestYSize / (gates.size());
130
            yOffset = - largestYSize / 2 + ySpacing / 2;
131
        }
132
 
133
        // Draw gates onto canvas
134
        for (int j = 0; j < gates.size(); j++) {
135
            scene->addItem(gates[j]);
136
            connect(gates[j], SIGNAL(updateStatus(QString)), this, SIGNAL(updateStatus(QString)));
137
            gates[j]->setCanvasPosition(xOffset, yOffset);
138
            yOffset += ySpacing;
139
        }
140
 
141
        xOffset += CANVAS_GATE_X_SPACING;
142
    }
143
 
144
    /*
145
    // Go through and calculate wiring region between gate objects
146
    wireSpace *vSpacing;
147
    for (int i = 1; i < circuit->gatesPerLevel.keys().size() - 1; i++) {
148
        int level = circuit->gatesPerLevel.keys()[i];
149
        QList<Gate_BASE*> gates = circuit->gatesPerLevel[level];
150
 
151
        // Compute and save top region
152
        QRectF topSpace = QRectF(gates[0]->x(), -largestYSize / 2, gates[0]->xSize, gates[0]->y() + largestYSize / 2);
153
        vSpacing = new wireSpace;
154
        vSpacing->region = topSpace;
155
        circuit->wireVSpacing[level].append(vSpacing);
156
 
157
        // Compute and save intermediate regions
158
        for (int j = 0; j < gates.size() - 1; j++) {
159
            QRectF midSpace;
160
            if (gates[j]->xSize >= gates[j+1]->xSize) {
161
                midSpace = QRectF(gates[j]->x(), gates[j]->y() + gates[j]->ySize, gates[j]->xSize, gates[j+1]->y() - (gates[j]->y() + gates[j]->ySize));
162
            } else {
163
                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));
164
            }
165
 
166
            vSpacing = new wireSpace;
167
            vSpacing->region = midSpace;
168
            circuit->wireVSpacing[level].append(vSpacing);
169
        }
170
 
171
        // Compute and save bottom region
172
        Gate_BASE *lastGate = gates[gates.size() - 1];
173
        QRectF botSpace = QRectF(lastGate->x(), lastGate->y() + lastGate->ySize, lastGate->xSize, largestYSize / 2 - (lastGate->y() + lastGate->ySize));
174
        vSpacing = new wireSpace;
175
        vSpacing->region = botSpace;
176
        circuit->wireVSpacing[level].append(vSpacing);
177
 
178
        // Draw regions in debug mode
179
#ifdef _DEBUG
180
        for (int j = 0; j < circuit->wireVSpacing[level].size(); j++)
181
            scene->addRect(circuit->wireVSpacing[level][j]->region, debugPen, QBrush(QColor(COLOR_WIRE_REGION_V)));
182
#endif
183
    }*/
184
 
185
    /*
186
    // Go through and calculate wiring region between levels
187
    wireSpace *hSpacing;
188
    for (int i = 0; i < circuit->gatesPerLevel.keys().size() - 1; i++) {
189
        int level = circuit->gatesPerLevel.keys()[i];
190
        QList<Gate_BASE*> gates = circuit->gatesPerLevel[level];
191
 
192
        // Compute the max X position for this level and min X position for next level
193
 
194
    }*/
195
 
196
 
197
    // Instantiate wires for each output->input connection on each gate
198
    QList<int> gateIDs = circuit->gateIndex.keys();
199
    for (int i = 0; i < gateIDs.size(); i++) {
200
        Gate_BASE *tmp = circuit->gateIndex[gateIDs[i]];
201
        // Connect each gate's input to other gate's output
202
        for (int j = 0; j < tmp->fanInGates.size(); j++) {
203
            Wire *wire = new Wire();
204
            wire->setPoints(tmp->fanInGates[j], tmp, j);
205
            // Store wires in gates on both ends
206
            tmp->gateInputWires.append(wire);
207
            tmp->fanInGates[j]->gateOutputWires.append(wire);
208
            // Save wire information into circuit
209
            circuit->wires.append(wire);
210
            connect(wire, SIGNAL(updateStatus(QString)), this, SIGNAL(updateStatus(QString)));
211
            connect(circuit, SIGNAL(toggleShowWireValues()), wire, SLOT(toggleShowValues()));
212
            scene->addItem(wire);
213
        }
214
    }
215
 
216
    scene->update();
217
    emit updateStatus("Circuit file successfully loaded");
218
}
219
 
220
/**
221
 * Zooms the canvas using matrix scaling
222
 */
223
void Canvas::zoomCanvas(int level)
224
{
225
    zoomLevel = level;
226
 
227
    qreal scale = qPow(qreal(2), (zoomLevel - 160) / qreal(40));
228
 
229
    QMatrix matrix;
230
    matrix.scale(scale,scale);
231
 
232
    setMatrix(matrix);
233
}
234
 
235
#ifndef QT_NO_WHEELEVENT
236
void Canvas::wheelEvent(QWheelEvent *event)
237
{
238
    // Zoom canvas on scroll wheel
239
    if (event->delta() > 0) {
240
        zoomCanvas(zoomLevel + 5);
241
        emit updateZoomSlider(zoomLevel + 5);
242
    } else {
243
        zoomCanvas(zoomLevel - 5);
244
        emit updateZoomSlider(zoomLevel - 5);
245
    }
246
    event->accept();
247
}
248
#endif
249
 
250
void Canvas::mousePressEvent(QMouseEvent *event)
251
{
252
    // If CTRL is held down, pan the canvas
253
    if (event->modifiers() & Qt::ControlModifier) {
254
        _pan = true;
255
        _panStartX = event->x();
256
        _panStartY = event->y();
257
        setCursor(Qt::ClosedHandCursor);
258
        event->accept();
259
        return;
260
    }
261
 
262
    if (circuit != NULL && circuit->circuitLoaded) {
263
        // Clear any previously selected gates and wires
264
        for (int i = 0; i < circuit->gatesPerLevel.size(); i++) {
265
            QList<Gate_BASE*> gates = circuit->gatesPerLevel[i];
266
            for (int j = 0; j < gates.size(); j++) {
267
                gates[j]->setHighlight(false, QColor(0,0,0,255));
268
            }
269
        }
270
        for (int i = 0; i < circuit->wires.size(); i++) {
271
            circuit->wires[i]->setHighlight(false, QColor(0,0,0,255));
272
        }
273
        updateStatus("");
274
    }
275
 
276
    // If not panning, propogate event to child objects
277
    QGraphicsView::mousePressEvent(event);
278
}
279
 
280
void Canvas::mouseMoveEvent(QMouseEvent *event)
281
{
282
    // Process panning if active
283
    if (_pan) {
284
        horizontalScrollBar()->setValue(horizontalScrollBar()->value() - (event->x() - _panStartX));
285
        verticalScrollBar()->setValue(verticalScrollBar()->value() - (event->y() - _panStartY));
286
        _panStartX = event->x();
287
        _panStartY = event->y();
288
        event->accept();
289
        return;
290
    }
291
 
292
    // Otherwise propogate event to child objects
293
    QGraphicsView::mouseMoveEvent(event);
294
}
295
 
296
void Canvas::mouseReleaseEvent(QMouseEvent *event)
297
{
298
    // Stop panning if active
299
    _pan = false;
300
    setCursor(Qt::ArrowCursor);
301
    event->accept();
302
 
303
    // Propogate event to child objects
304
    QGraphicsView::mouseReleaseEvent(event);
305
}