Initial Commit
96
CircuitBuffer.cpp
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
#include "CircuitBuffer.h"
|
||||||
|
|
||||||
|
#include "Part.h"
|
||||||
|
#include "Wire.h"
|
||||||
|
#include "Connector.h"
|
||||||
|
#include "Scene.h"
|
||||||
|
#include "Logic.h"
|
||||||
|
|
||||||
|
#include "Parts/IntegratedCircuit.h"
|
||||||
|
|
||||||
|
CircuitBuffer::CircuitBuffer()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void CircuitBuffer::addFromScene(const QList<Part*> &parts, const QList<Wire*>& wires)
|
||||||
|
{
|
||||||
|
// Maps the pointer of every given part to the corresponding pointer to an element in m_parts
|
||||||
|
QMap<Part*, PartData*> partPtrToDataPtr;
|
||||||
|
|
||||||
|
for(auto part : parts)
|
||||||
|
{
|
||||||
|
// Create partData
|
||||||
|
PartData partData;
|
||||||
|
partData.type = part->m_partType;
|
||||||
|
partData.pos = part->pos();
|
||||||
|
if(part->partType() == PartType::IntegratedCircuit)
|
||||||
|
partData.icFilename = ((IntegratedCircuit*)part)->filename();
|
||||||
|
else
|
||||||
|
partData.icFilename = QString();
|
||||||
|
// Add part to parts list
|
||||||
|
m_parts.append(partData);
|
||||||
|
// Make it possible to find partData pointer with Part pointer
|
||||||
|
partPtrToDataPtr.insert(part, &m_parts.last());
|
||||||
|
}
|
||||||
|
for(auto wire : wires)
|
||||||
|
{
|
||||||
|
auto wireInputPart = (Part*)wire->m_connectorInput->parentItem();
|
||||||
|
auto wireOutputPart = (Part*)wire->m_connectorOutput->parentItem();
|
||||||
|
|
||||||
|
// Create wireData
|
||||||
|
WireData wireData;
|
||||||
|
wireData.inputPart = partPtrToDataPtr[wireInputPart];
|
||||||
|
wireData.inputPartConnectorIdx = wireInputPart->m_outputs.indexOf(wire->m_connectorInput);
|
||||||
|
wireData.outputPart = partPtrToDataPtr[wireOutputPart];
|
||||||
|
wireData.outputPartConnectorIdx = wireOutputPart->m_inputs.indexOf(wire->m_connectorOutput);
|
||||||
|
m_wires.append(wireData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QPair<QList<Part*>, QList<Wire*>> CircuitBuffer::addIntoScene(Scene* scene, QPointF posOffset) const
|
||||||
|
{
|
||||||
|
QList<Part*> allocatedParts;
|
||||||
|
QList<Wire*> allocatedWires;
|
||||||
|
|
||||||
|
QMap<const PartData*, Part*> dataToAllocatedPart;
|
||||||
|
|
||||||
|
for(auto& partData : m_parts)
|
||||||
|
{
|
||||||
|
Part* part;
|
||||||
|
if(partData.type == PartType::IntegratedCircuit)
|
||||||
|
part = scene->m_logic->createIC(partData.icFilename, partData.pos + posOffset);
|
||||||
|
else
|
||||||
|
part = scene->m_logic->createPart(partData.type, partData.pos + posOffset);
|
||||||
|
dataToAllocatedPart.insert(&partData, part);
|
||||||
|
|
||||||
|
allocatedParts.append(part);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto& wireData : m_wires)
|
||||||
|
{
|
||||||
|
// input and output are relative to the wire
|
||||||
|
Part* inputPart = dataToAllocatedPart[wireData.inputPart];
|
||||||
|
Connector* inputConnector = inputPart->m_outputs[wireData.inputPartConnectorIdx];
|
||||||
|
Part* outputPart = dataToAllocatedPart[wireData.outputPart];
|
||||||
|
Connector* outputConnector = outputPart->m_inputs[wireData.outputPartConnectorIdx];
|
||||||
|
Wire* wire = scene->m_logic->createWire(inputConnector, outputConnector);
|
||||||
|
|
||||||
|
allocatedWires.append(wire);
|
||||||
|
}
|
||||||
|
return QPair<QList<Part*>, QList<Wire*>>(allocatedParts, allocatedWires);
|
||||||
|
}
|
||||||
|
|
||||||
|
QPointF CircuitBuffer::getAvgPartPos()
|
||||||
|
{
|
||||||
|
QPointF sum(0.f, 0.f);
|
||||||
|
for(auto part : m_parts)
|
||||||
|
sum += part.pos;
|
||||||
|
return sum / m_parts.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CircuitBuffer::clear()
|
||||||
|
{
|
||||||
|
m_parts.clear();
|
||||||
|
m_wires.clear();
|
||||||
|
}
|
44
CircuitBuffer.h
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#ifndef CIRCUITBUFFER_H
|
||||||
|
#define CIRCUITBUFFER_H
|
||||||
|
|
||||||
|
class Part;
|
||||||
|
class Wire;
|
||||||
|
class Scene;
|
||||||
|
|
||||||
|
#include <QList>
|
||||||
|
#include <QPointF>
|
||||||
|
|
||||||
|
#include "ePartType.h"
|
||||||
|
|
||||||
|
class CircuitBuffer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct PartData
|
||||||
|
{
|
||||||
|
PartType::PartType type;
|
||||||
|
QPointF pos;
|
||||||
|
QString icFilename;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WireData
|
||||||
|
{
|
||||||
|
PartData* inputPart;
|
||||||
|
int inputPartConnectorIdx;
|
||||||
|
PartData* outputPart;
|
||||||
|
int outputPartConnectorIdx;
|
||||||
|
};
|
||||||
|
|
||||||
|
CircuitBuffer();
|
||||||
|
|
||||||
|
void addFromScene(const QList<Part*>& parts, const QList<Wire*>& wires);
|
||||||
|
QPair<QList<Part*>, QList<Wire*>> addIntoScene(Scene* scene, QPointF posOffset) const;
|
||||||
|
QPointF getAvgPartPos();
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QList<PartData> m_parts;
|
||||||
|
QList<WireData> m_wires;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CIRCUITBUFFER_H
|
88
CircuitSimulator.pro
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
QT += core gui
|
||||||
|
|
||||||
|
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||||
|
|
||||||
|
CONFIG += c++11
|
||||||
|
|
||||||
|
# The following define makes your compiler emit warnings if you use
|
||||||
|
# any Qt feature that has been marked deprecated (the exact warnings
|
||||||
|
# depend on your compiler). Please consult the documentation of the
|
||||||
|
# deprecated API in order to know how to port your code away from it.
|
||||||
|
DEFINES += QT_DEPRECATED_WARNINGS
|
||||||
|
|
||||||
|
# You can also make your code fail to compile if it uses deprecated APIs.
|
||||||
|
# In order to do so, uncomment the following line.
|
||||||
|
# You can also select to disable deprecated APIs only up to a certain version of Qt.
|
||||||
|
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
CircuitBuffer.cpp \
|
||||||
|
Logic.cpp \
|
||||||
|
Parts/AndGate.cpp \
|
||||||
|
Parts/BufferGate.cpp \
|
||||||
|
Parts/HighConstant.cpp \
|
||||||
|
Parts/IntegratedCircuit.cpp \
|
||||||
|
Parts/LightBulb.cpp \
|
||||||
|
Parts/LowConstant.cpp \
|
||||||
|
Parts/NandGate.cpp \
|
||||||
|
Parts/NorGate.cpp \
|
||||||
|
Parts/NotGate.cpp \
|
||||||
|
Parts/OrGate.cpp \
|
||||||
|
Parts/ToggleButton.cpp \
|
||||||
|
Parts/XnorGate.cpp \
|
||||||
|
Parts/XorGate.cpp \
|
||||||
|
Connector.cpp \
|
||||||
|
FileHandler.cpp \
|
||||||
|
MainWindow.cpp \
|
||||||
|
Part.cpp \
|
||||||
|
Scene.cpp \
|
||||||
|
UndoCommands/AddPart.cpp \
|
||||||
|
UndoCommands/AddWire.cpp \
|
||||||
|
UndoCommands/CopyParts.cpp \
|
||||||
|
UndoCommands/MoveParts.cpp \
|
||||||
|
UndoCommands/RemoveParts.cpp \
|
||||||
|
UndoCommands/RemoveWire.cpp \
|
||||||
|
Wire.cpp \
|
||||||
|
main.cpp
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
CircuitBuffer.h \
|
||||||
|
Logic.h \
|
||||||
|
Parts/AndGate.h \
|
||||||
|
Parts/BufferGate.h \
|
||||||
|
Parts/HighConstant.h \
|
||||||
|
Parts/IntegratedCircuit.h \
|
||||||
|
Parts/LightBulb.h \
|
||||||
|
Parts/LowConstant.h \
|
||||||
|
Parts/NandGate.h \
|
||||||
|
Parts/NorGate.h \
|
||||||
|
Parts/NotGate.h \
|
||||||
|
Parts/OrGate.h \
|
||||||
|
Parts/ToggleButton.h \
|
||||||
|
Parts/XnorGate.h \
|
||||||
|
Parts/XorGate.h \
|
||||||
|
Connector.h \
|
||||||
|
FileHandler.h \
|
||||||
|
MainWindow.h \
|
||||||
|
Part.h \
|
||||||
|
Scene.h \
|
||||||
|
UndoCommands/AddPart.h \
|
||||||
|
UndoCommands/AddWire.h \
|
||||||
|
UndoCommands/CopyParts.h \
|
||||||
|
UndoCommands/MoveParts.h \
|
||||||
|
UndoCommands/RemoveParts.h \
|
||||||
|
UndoCommands/RemoveWire.h \
|
||||||
|
Wire.h \
|
||||||
|
eConnectorType.h \
|
||||||
|
ePartType.h
|
||||||
|
|
||||||
|
FORMS += \
|
||||||
|
MainWindow.ui
|
||||||
|
|
||||||
|
# Default rules for deployment.
|
||||||
|
qnx: target.path = /tmp/$${TARGET}/bin
|
||||||
|
else: unix:!android: target.path = /opt/$${TARGET}/bin
|
||||||
|
!isEmpty(target.path): INSTALLS += target
|
||||||
|
|
||||||
|
RESOURCES += \
|
||||||
|
Resources.qrc
|
99
Connector.cpp
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
#include "Connector.h"
|
||||||
|
|
||||||
|
#include <QPainter>
|
||||||
|
#include "Part.h"
|
||||||
|
#include "MainWindow.h"
|
||||||
|
#include "Wire.h"
|
||||||
|
#include "eConnectorType.h"
|
||||||
|
#include "Scene.h"
|
||||||
|
|
||||||
|
|
||||||
|
// PUBLIC
|
||||||
|
Connector::Connector(Scene* scene, Part *parentPart, ConnectorType::ConnectorType side)
|
||||||
|
:m_scene(scene), m_connectorType(side)
|
||||||
|
{
|
||||||
|
setParentItem(parentPart);
|
||||||
|
|
||||||
|
setFlag(QGraphicsItem::ItemSendsScenePositionChanges);
|
||||||
|
}
|
||||||
|
|
||||||
|
QRectF Connector::boundingRect() const
|
||||||
|
{
|
||||||
|
if(m_connectorType == ConnectorType::Output)
|
||||||
|
return QRectF(-1, -4, 15, 8);
|
||||||
|
else
|
||||||
|
return QRectF(-14, -4, 15, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
QPainterPath Connector::shape() const
|
||||||
|
{
|
||||||
|
QPainterPath path;
|
||||||
|
if(m_connectorType == ConnectorType::Output)
|
||||||
|
path.addRect(-1, -4, 15, 8);
|
||||||
|
else
|
||||||
|
path.addRect(-14, -4, 15, 8);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Connector::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
|
||||||
|
{
|
||||||
|
QPen pen = painter->pen();
|
||||||
|
pen.setWidth(2);
|
||||||
|
if(parentItem()->isSelected())
|
||||||
|
pen.setColor(((Part*)parentItem())->m_penColorSelected);
|
||||||
|
else
|
||||||
|
pen.setColor(((Part*)parentItem())->m_penColorNormal);
|
||||||
|
painter->setPen(pen);
|
||||||
|
QBrush brush = painter->brush();
|
||||||
|
if(m_selected)
|
||||||
|
{
|
||||||
|
brush.setStyle(Qt::BrushStyle::SolidPattern);
|
||||||
|
brush.setColor(Qt::green);
|
||||||
|
}
|
||||||
|
painter->setBrush(brush);
|
||||||
|
if(m_connectorType == ConnectorType::Output)
|
||||||
|
{
|
||||||
|
painter->drawLine(2, 0, 6, 0);
|
||||||
|
painter->drawEllipse(7, -3, 6, 6);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
painter->drawLine(-6, 0, -2, 0);
|
||||||
|
painter->drawEllipse(-13, -3, 6, 6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Connector::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||||||
|
{
|
||||||
|
m_scene->connectorClicked(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant Connector::itemChange(GraphicsItemChange change, const QVariant &value)
|
||||||
|
{
|
||||||
|
if(change == ItemScenePositionHasChanged)
|
||||||
|
{
|
||||||
|
// Update wires
|
||||||
|
for(auto i : m_wires)
|
||||||
|
i->updateLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConnectorType::ConnectorType Connector::connectorType()
|
||||||
|
{
|
||||||
|
return m_connectorType;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PRIVATE
|
||||||
|
void Connector::select()
|
||||||
|
{
|
||||||
|
m_selected = true;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Connector::unselect()
|
||||||
|
{
|
||||||
|
m_selected = false;
|
||||||
|
update();
|
||||||
|
}
|
47
Connector.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#ifndef CIRCUITCONNECTION_H
|
||||||
|
#define CIRCUITCONNECTION_H
|
||||||
|
|
||||||
|
#include <QGraphicsItem>
|
||||||
|
#include <QList>
|
||||||
|
#include "eConnectorType.h"
|
||||||
|
|
||||||
|
class Part;
|
||||||
|
class Wire;
|
||||||
|
class Scene;
|
||||||
|
|
||||||
|
class Connector : public QGraphicsItem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
friend class Scene;
|
||||||
|
friend class Logic;
|
||||||
|
friend class Part;
|
||||||
|
friend class Wire;
|
||||||
|
friend class AddPart;
|
||||||
|
friend class RemoveParts;
|
||||||
|
friend class CopyParts;
|
||||||
|
|
||||||
|
friend class MainWindow;
|
||||||
|
|
||||||
|
Connector(Scene* scene, Part *parentPart, ConnectorType::ConnectorType side);
|
||||||
|
|
||||||
|
QRectF boundingRect() const override; // For drawing
|
||||||
|
QPainterPath shape() const override; // For selection ("Hitbox")
|
||||||
|
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
|
||||||
|
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
|
||||||
|
QVariant itemChange(GraphicsItemChange change, const QVariant &value) override;
|
||||||
|
|
||||||
|
ConnectorType::ConnectorType connectorType();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Scene* m_scene;
|
||||||
|
|
||||||
|
QList<Wire*> m_wires;
|
||||||
|
ConnectorType::ConnectorType m_connectorType;
|
||||||
|
bool m_state = false;
|
||||||
|
bool m_selected = false; // Separate from regular selection, for creating connections
|
||||||
|
|
||||||
|
void select(); // Called by MainWindow
|
||||||
|
void unselect(); // Called by MainWindow
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CIRCUITCONNECTION_H
|
139
FileHandler.cpp
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
#include "FileHandler.h"
|
||||||
|
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QTextStream>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QDir>
|
||||||
|
#include "Scene.h"
|
||||||
|
#include "Part.h"
|
||||||
|
#include "Wire.h"
|
||||||
|
#include "Connector.h"
|
||||||
|
#include "Logic.h"
|
||||||
|
#include "MainWindow.h"
|
||||||
|
|
||||||
|
#include "Parts/IntegratedCircuit.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
FileHandler::FileHandler(Logic* logic)
|
||||||
|
:m_logic(logic)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileHandler::exists(QString filename)
|
||||||
|
{
|
||||||
|
QFile file(filename);
|
||||||
|
return file.exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileHandler::save(QString filename)
|
||||||
|
{
|
||||||
|
QFile file(filename);
|
||||||
|
|
||||||
|
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
QTextStream fOut(&file);
|
||||||
|
|
||||||
|
fOut << "[parts]\n";
|
||||||
|
for(auto part : m_logic->m_parts)
|
||||||
|
{
|
||||||
|
fOut << part << " " << part->m_partType << " " << part->pos().x() << " " << part->pos().y();
|
||||||
|
if(part->m_partType == PartType::IntegratedCircuit)
|
||||||
|
{
|
||||||
|
// Strip out IC file path
|
||||||
|
QFileInfo fileInfo(((IntegratedCircuit*)part)->filename());
|
||||||
|
QString icFile(fileInfo.fileName());
|
||||||
|
fOut << " " << icFile;
|
||||||
|
}
|
||||||
|
fOut << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
fOut << "[wires]\n";
|
||||||
|
for(auto wire : m_logic->m_wires)
|
||||||
|
{
|
||||||
|
auto wireInputPart = (Part*)wire->m_connectorInput->parentItem();
|
||||||
|
auto wireOutputPart = (Part*)wire->m_connectorOutput->parentItem();
|
||||||
|
|
||||||
|
fOut << wireInputPart << " " << wireInputPart->m_outputs.indexOf(wire->m_connectorInput) << " " << wireOutputPart << " " << wireOutputPart->m_inputs.indexOf(wire->m_connectorOutput) << "\n";
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileHandler::open(QString filename)
|
||||||
|
{
|
||||||
|
//TODO: Make it possible to load IC filenames with spaces
|
||||||
|
|
||||||
|
QFile file(filename);
|
||||||
|
|
||||||
|
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
enum Sector
|
||||||
|
{
|
||||||
|
Parts,
|
||||||
|
Wires
|
||||||
|
};
|
||||||
|
|
||||||
|
Sector currentSector;
|
||||||
|
|
||||||
|
// A .csim file stores all parts with IDs, this map simply keeps track of which ID was given which pointer
|
||||||
|
QMap<QString, Part*> idPartPointerMap;
|
||||||
|
|
||||||
|
while (!file.atEnd()) {
|
||||||
|
QString line = file.readLine();
|
||||||
|
if(line.contains("[parts]"))
|
||||||
|
currentSector = Parts;
|
||||||
|
else if(line.contains("[wires]"))
|
||||||
|
currentSector = Wires;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QVector<QString> words;
|
||||||
|
QString currWord;
|
||||||
|
for(QChar c : line)
|
||||||
|
{
|
||||||
|
if(c == QChar::Space)
|
||||||
|
{
|
||||||
|
words.append(currWord);
|
||||||
|
currWord.clear();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
currWord.append(c);
|
||||||
|
}
|
||||||
|
words.append(currWord);
|
||||||
|
// Remove the \n from last word
|
||||||
|
words.last().remove(words.last().length() - 1, 1);
|
||||||
|
|
||||||
|
if(words.length() < 4)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(currentSector == Parts)
|
||||||
|
{
|
||||||
|
PartType::PartType type = (PartType::PartType)words[1].toInt();
|
||||||
|
QPointF pos = QPointF(words[2].toFloat(), words[3].toFloat());
|
||||||
|
Part* part;
|
||||||
|
if(type == PartType::IntegratedCircuit)
|
||||||
|
{
|
||||||
|
QDir icDir(filename);
|
||||||
|
icDir.cdUp();
|
||||||
|
QString icFilename = icDir.filePath(words[4]);
|
||||||
|
if(!QFile(icFilename).exists())
|
||||||
|
{
|
||||||
|
qFatal("Failed to open IC file: " + icFilename.toUtf8());
|
||||||
|
}
|
||||||
|
part = m_logic->createIC(icFilename, pos);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
part = m_logic->createPart(type, pos);
|
||||||
|
idPartPointerMap.insert(words[0], part);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto inputConnector = idPartPointerMap[words[0]]->m_outputs[words[1].toInt()];
|
||||||
|
auto outputConnector = idPartPointerMap[words[2]]->m_inputs[words[3].toInt()];
|
||||||
|
m_logic->createWire(inputConnector, outputConnector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
21
FileHandler.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#ifndef FILEHANDLER_H
|
||||||
|
#define FILEHANDLER_H
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
class Logic;
|
||||||
|
|
||||||
|
class FileHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FileHandler(Logic* logic);
|
||||||
|
|
||||||
|
bool exists(QString filename);
|
||||||
|
bool save(QString filename);
|
||||||
|
bool open(QString filename);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Logic* m_logic;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // FILEHANDLER_H
|
674
LICENSE
Normal file
@ -0,0 +1,674 @@
|
|||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The GNU General Public License is a free, copyleft license for
|
||||||
|
software and other kinds of works.
|
||||||
|
|
||||||
|
The licenses for most software and other practical works are designed
|
||||||
|
to take away your freedom to share and change the works. By contrast,
|
||||||
|
the GNU General Public License is intended to guarantee your freedom to
|
||||||
|
share and change all versions of a program--to make sure it remains free
|
||||||
|
software for all its users. We, the Free Software Foundation, use the
|
||||||
|
GNU General Public License for most of our software; it applies also to
|
||||||
|
any other work released this way by its authors. You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
them if you wish), that you receive source code or can get it if you
|
||||||
|
want it, that you can change the software or use pieces of it in new
|
||||||
|
free programs, and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to prevent others from denying you
|
||||||
|
these rights or asking you to surrender the rights. Therefore, you have
|
||||||
|
certain responsibilities if you distribute copies of the software, or if
|
||||||
|
you modify it: responsibilities to respect the freedom of others.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must pass on to the recipients the same
|
||||||
|
freedoms that you received. You must make sure that they, too, receive
|
||||||
|
or can get the source code. And you must show them these terms so they
|
||||||
|
know their rights.
|
||||||
|
|
||||||
|
Developers that use the GNU GPL protect your rights with two steps:
|
||||||
|
(1) assert copyright on the software, and (2) offer you this License
|
||||||
|
giving you legal permission to copy, distribute and/or modify it.
|
||||||
|
|
||||||
|
For the developers' and authors' protection, the GPL clearly explains
|
||||||
|
that there is no warranty for this free software. For both users' and
|
||||||
|
authors' sake, the GPL requires that modified versions be marked as
|
||||||
|
changed, so that their problems will not be attributed erroneously to
|
||||||
|
authors of previous versions.
|
||||||
|
|
||||||
|
Some devices are designed to deny users access to install or run
|
||||||
|
modified versions of the software inside them, although the manufacturer
|
||||||
|
can do so. This is fundamentally incompatible with the aim of
|
||||||
|
protecting users' freedom to change the software. The systematic
|
||||||
|
pattern of such abuse occurs in the area of products for individuals to
|
||||||
|
use, which is precisely where it is most unacceptable. Therefore, we
|
||||||
|
have designed this version of the GPL to prohibit the practice for those
|
||||||
|
products. If such problems arise substantially in other domains, we
|
||||||
|
stand ready to extend this provision to those domains in future versions
|
||||||
|
of the GPL, as needed to protect the freedom of users.
|
||||||
|
|
||||||
|
Finally, every program is threatened constantly by software patents.
|
||||||
|
States should not allow patents to restrict development and use of
|
||||||
|
software on general-purpose computers, but in those that do, we wish to
|
||||||
|
avoid the special danger that patents applied to a free program could
|
||||||
|
make it effectively proprietary. To prevent this, the GPL assures that
|
||||||
|
patents cannot be used to render the program non-free.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
0. Definitions.
|
||||||
|
|
||||||
|
"This License" refers to version 3 of the GNU General Public License.
|
||||||
|
|
||||||
|
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||||
|
works, such as semiconductor masks.
|
||||||
|
|
||||||
|
"The Program" refers to any copyrightable work licensed under this
|
||||||
|
License. Each licensee is addressed as "you". "Licensees" and
|
||||||
|
"recipients" may be individuals or organizations.
|
||||||
|
|
||||||
|
To "modify" a work means to copy from or adapt all or part of the work
|
||||||
|
in a fashion requiring copyright permission, other than the making of an
|
||||||
|
exact copy. The resulting work is called a "modified version" of the
|
||||||
|
earlier work or a work "based on" the earlier work.
|
||||||
|
|
||||||
|
A "covered work" means either the unmodified Program or a work based
|
||||||
|
on the Program.
|
||||||
|
|
||||||
|
To "propagate" a work means to do anything with it that, without
|
||||||
|
permission, would make you directly or secondarily liable for
|
||||||
|
infringement under applicable copyright law, except executing it on a
|
||||||
|
computer or modifying a private copy. Propagation includes copying,
|
||||||
|
distribution (with or without modification), making available to the
|
||||||
|
public, and in some countries other activities as well.
|
||||||
|
|
||||||
|
To "convey" a work means any kind of propagation that enables other
|
||||||
|
parties to make or receive copies. Mere interaction with a user through
|
||||||
|
a computer network, with no transfer of a copy, is not conveying.
|
||||||
|
|
||||||
|
An interactive user interface displays "Appropriate Legal Notices"
|
||||||
|
to the extent that it includes a convenient and prominently visible
|
||||||
|
feature that (1) displays an appropriate copyright notice, and (2)
|
||||||
|
tells the user that there is no warranty for the work (except to the
|
||||||
|
extent that warranties are provided), that licensees may convey the
|
||||||
|
work under this License, and how to view a copy of this License. If
|
||||||
|
the interface presents a list of user commands or options, such as a
|
||||||
|
menu, a prominent item in the list meets this criterion.
|
||||||
|
|
||||||
|
1. Source Code.
|
||||||
|
|
||||||
|
The "source code" for a work means the preferred form of the work
|
||||||
|
for making modifications to it. "Object code" means any non-source
|
||||||
|
form of a work.
|
||||||
|
|
||||||
|
A "Standard Interface" means an interface that either is an official
|
||||||
|
standard defined by a recognized standards body, or, in the case of
|
||||||
|
interfaces specified for a particular programming language, one that
|
||||||
|
is widely used among developers working in that language.
|
||||||
|
|
||||||
|
The "System Libraries" of an executable work include anything, other
|
||||||
|
than the work as a whole, that (a) is included in the normal form of
|
||||||
|
packaging a Major Component, but which is not part of that Major
|
||||||
|
Component, and (b) serves only to enable use of the work with that
|
||||||
|
Major Component, or to implement a Standard Interface for which an
|
||||||
|
implementation is available to the public in source code form. A
|
||||||
|
"Major Component", in this context, means a major essential component
|
||||||
|
(kernel, window system, and so on) of the specific operating system
|
||||||
|
(if any) on which the executable work runs, or a compiler used to
|
||||||
|
produce the work, or an object code interpreter used to run it.
|
||||||
|
|
||||||
|
The "Corresponding Source" for a work in object code form means all
|
||||||
|
the source code needed to generate, install, and (for an executable
|
||||||
|
work) run the object code and to modify the work, including scripts to
|
||||||
|
control those activities. However, it does not include the work's
|
||||||
|
System Libraries, or general-purpose tools or generally available free
|
||||||
|
programs which are used unmodified in performing those activities but
|
||||||
|
which are not part of the work. For example, Corresponding Source
|
||||||
|
includes interface definition files associated with source files for
|
||||||
|
the work, and the source code for shared libraries and dynamically
|
||||||
|
linked subprograms that the work is specifically designed to require,
|
||||||
|
such as by intimate data communication or control flow between those
|
||||||
|
subprograms and other parts of the work.
|
||||||
|
|
||||||
|
The Corresponding Source need not include anything that users
|
||||||
|
can regenerate automatically from other parts of the Corresponding
|
||||||
|
Source.
|
||||||
|
|
||||||
|
The Corresponding Source for a work in source code form is that
|
||||||
|
same work.
|
||||||
|
|
||||||
|
2. Basic Permissions.
|
||||||
|
|
||||||
|
All rights granted under this License are granted for the term of
|
||||||
|
copyright on the Program, and are irrevocable provided the stated
|
||||||
|
conditions are met. This License explicitly affirms your unlimited
|
||||||
|
permission to run the unmodified Program. The output from running a
|
||||||
|
covered work is covered by this License only if the output, given its
|
||||||
|
content, constitutes a covered work. This License acknowledges your
|
||||||
|
rights of fair use or other equivalent, as provided by copyright law.
|
||||||
|
|
||||||
|
You may make, run and propagate covered works that you do not
|
||||||
|
convey, without conditions so long as your license otherwise remains
|
||||||
|
in force. You may convey covered works to others for the sole purpose
|
||||||
|
of having them make modifications exclusively for you, or provide you
|
||||||
|
with facilities for running those works, provided that you comply with
|
||||||
|
the terms of this License in conveying all material for which you do
|
||||||
|
not control copyright. Those thus making or running the covered works
|
||||||
|
for you must do so exclusively on your behalf, under your direction
|
||||||
|
and control, on terms that prohibit them from making any copies of
|
||||||
|
your copyrighted material outside their relationship with you.
|
||||||
|
|
||||||
|
Conveying under any other circumstances is permitted solely under
|
||||||
|
the conditions stated below. Sublicensing is not allowed; section 10
|
||||||
|
makes it unnecessary.
|
||||||
|
|
||||||
|
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||||
|
|
||||||
|
No covered work shall be deemed part of an effective technological
|
||||||
|
measure under any applicable law fulfilling obligations under article
|
||||||
|
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||||
|
similar laws prohibiting or restricting circumvention of such
|
||||||
|
measures.
|
||||||
|
|
||||||
|
When you convey a covered work, you waive any legal power to forbid
|
||||||
|
circumvention of technological measures to the extent such circumvention
|
||||||
|
is effected by exercising rights under this License with respect to
|
||||||
|
the covered work, and you disclaim any intention to limit operation or
|
||||||
|
modification of the work as a means of enforcing, against the work's
|
||||||
|
users, your or third parties' legal rights to forbid circumvention of
|
||||||
|
technological measures.
|
||||||
|
|
||||||
|
4. Conveying Verbatim Copies.
|
||||||
|
|
||||||
|
You may convey verbatim copies of the Program's source code as you
|
||||||
|
receive it, in any medium, provided that you conspicuously and
|
||||||
|
appropriately publish on each copy an appropriate copyright notice;
|
||||||
|
keep intact all notices stating that this License and any
|
||||||
|
non-permissive terms added in accord with section 7 apply to the code;
|
||||||
|
keep intact all notices of the absence of any warranty; and give all
|
||||||
|
recipients a copy of this License along with the Program.
|
||||||
|
|
||||||
|
You may charge any price or no price for each copy that you convey,
|
||||||
|
and you may offer support or warranty protection for a fee.
|
||||||
|
|
||||||
|
5. Conveying Modified Source Versions.
|
||||||
|
|
||||||
|
You may convey a work based on the Program, or the modifications to
|
||||||
|
produce it from the Program, in the form of source code under the
|
||||||
|
terms of section 4, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) The work must carry prominent notices stating that you modified
|
||||||
|
it, and giving a relevant date.
|
||||||
|
|
||||||
|
b) The work must carry prominent notices stating that it is
|
||||||
|
released under this License and any conditions added under section
|
||||||
|
7. This requirement modifies the requirement in section 4 to
|
||||||
|
"keep intact all notices".
|
||||||
|
|
||||||
|
c) You must license the entire work, as a whole, under this
|
||||||
|
License to anyone who comes into possession of a copy. This
|
||||||
|
License will therefore apply, along with any applicable section 7
|
||||||
|
additional terms, to the whole of the work, and all its parts,
|
||||||
|
regardless of how they are packaged. This License gives no
|
||||||
|
permission to license the work in any other way, but it does not
|
||||||
|
invalidate such permission if you have separately received it.
|
||||||
|
|
||||||
|
d) If the work has interactive user interfaces, each must display
|
||||||
|
Appropriate Legal Notices; however, if the Program has interactive
|
||||||
|
interfaces that do not display Appropriate Legal Notices, your
|
||||||
|
work need not make them do so.
|
||||||
|
|
||||||
|
A compilation of a covered work with other separate and independent
|
||||||
|
works, which are not by their nature extensions of the covered work,
|
||||||
|
and which are not combined with it such as to form a larger program,
|
||||||
|
in or on a volume of a storage or distribution medium, is called an
|
||||||
|
"aggregate" if the compilation and its resulting copyright are not
|
||||||
|
used to limit the access or legal rights of the compilation's users
|
||||||
|
beyond what the individual works permit. Inclusion of a covered work
|
||||||
|
in an aggregate does not cause this License to apply to the other
|
||||||
|
parts of the aggregate.
|
||||||
|
|
||||||
|
6. Conveying Non-Source Forms.
|
||||||
|
|
||||||
|
You may convey a covered work in object code form under the terms
|
||||||
|
of sections 4 and 5, provided that you also convey the
|
||||||
|
machine-readable Corresponding Source under the terms of this License,
|
||||||
|
in one of these ways:
|
||||||
|
|
||||||
|
a) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by the
|
||||||
|
Corresponding Source fixed on a durable physical medium
|
||||||
|
customarily used for software interchange.
|
||||||
|
|
||||||
|
b) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by a
|
||||||
|
written offer, valid for at least three years and valid for as
|
||||||
|
long as you offer spare parts or customer support for that product
|
||||||
|
model, to give anyone who possesses the object code either (1) a
|
||||||
|
copy of the Corresponding Source for all the software in the
|
||||||
|
product that is covered by this License, on a durable physical
|
||||||
|
medium customarily used for software interchange, for a price no
|
||||||
|
more than your reasonable cost of physically performing this
|
||||||
|
conveying of source, or (2) access to copy the
|
||||||
|
Corresponding Source from a network server at no charge.
|
||||||
|
|
||||||
|
c) Convey individual copies of the object code with a copy of the
|
||||||
|
written offer to provide the Corresponding Source. This
|
||||||
|
alternative is allowed only occasionally and noncommercially, and
|
||||||
|
only if you received the object code with such an offer, in accord
|
||||||
|
with subsection 6b.
|
||||||
|
|
||||||
|
d) Convey the object code by offering access from a designated
|
||||||
|
place (gratis or for a charge), and offer equivalent access to the
|
||||||
|
Corresponding Source in the same way through the same place at no
|
||||||
|
further charge. You need not require recipients to copy the
|
||||||
|
Corresponding Source along with the object code. If the place to
|
||||||
|
copy the object code is a network server, the Corresponding Source
|
||||||
|
may be on a different server (operated by you or a third party)
|
||||||
|
that supports equivalent copying facilities, provided you maintain
|
||||||
|
clear directions next to the object code saying where to find the
|
||||||
|
Corresponding Source. Regardless of what server hosts the
|
||||||
|
Corresponding Source, you remain obligated to ensure that it is
|
||||||
|
available for as long as needed to satisfy these requirements.
|
||||||
|
|
||||||
|
e) Convey the object code using peer-to-peer transmission, provided
|
||||||
|
you inform other peers where the object code and Corresponding
|
||||||
|
Source of the work are being offered to the general public at no
|
||||||
|
charge under subsection 6d.
|
||||||
|
|
||||||
|
A separable portion of the object code, whose source code is excluded
|
||||||
|
from the Corresponding Source as a System Library, need not be
|
||||||
|
included in conveying the object code work.
|
||||||
|
|
||||||
|
A "User Product" is either (1) a "consumer product", which means any
|
||||||
|
tangible personal property which is normally used for personal, family,
|
||||||
|
or household purposes, or (2) anything designed or sold for incorporation
|
||||||
|
into a dwelling. In determining whether a product is a consumer product,
|
||||||
|
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||||
|
product received by a particular user, "normally used" refers to a
|
||||||
|
typical or common use of that class of product, regardless of the status
|
||||||
|
of the particular user or of the way in which the particular user
|
||||||
|
actually uses, or expects or is expected to use, the product. A product
|
||||||
|
is a consumer product regardless of whether the product has substantial
|
||||||
|
commercial, industrial or non-consumer uses, unless such uses represent
|
||||||
|
the only significant mode of use of the product.
|
||||||
|
|
||||||
|
"Installation Information" for a User Product means any methods,
|
||||||
|
procedures, authorization keys, or other information required to install
|
||||||
|
and execute modified versions of a covered work in that User Product from
|
||||||
|
a modified version of its Corresponding Source. The information must
|
||||||
|
suffice to ensure that the continued functioning of the modified object
|
||||||
|
code is in no case prevented or interfered with solely because
|
||||||
|
modification has been made.
|
||||||
|
|
||||||
|
If you convey an object code work under this section in, or with, or
|
||||||
|
specifically for use in, a User Product, and the conveying occurs as
|
||||||
|
part of a transaction in which the right of possession and use of the
|
||||||
|
User Product is transferred to the recipient in perpetuity or for a
|
||||||
|
fixed term (regardless of how the transaction is characterized), the
|
||||||
|
Corresponding Source conveyed under this section must be accompanied
|
||||||
|
by the Installation Information. But this requirement does not apply
|
||||||
|
if neither you nor any third party retains the ability to install
|
||||||
|
modified object code on the User Product (for example, the work has
|
||||||
|
been installed in ROM).
|
||||||
|
|
||||||
|
The requirement to provide Installation Information does not include a
|
||||||
|
requirement to continue to provide support service, warranty, or updates
|
||||||
|
for a work that has been modified or installed by the recipient, or for
|
||||||
|
the User Product in which it has been modified or installed. Access to a
|
||||||
|
network may be denied when the modification itself materially and
|
||||||
|
adversely affects the operation of the network or violates the rules and
|
||||||
|
protocols for communication across the network.
|
||||||
|
|
||||||
|
Corresponding Source conveyed, and Installation Information provided,
|
||||||
|
in accord with this section must be in a format that is publicly
|
||||||
|
documented (and with an implementation available to the public in
|
||||||
|
source code form), and must require no special password or key for
|
||||||
|
unpacking, reading or copying.
|
||||||
|
|
||||||
|
7. Additional Terms.
|
||||||
|
|
||||||
|
"Additional permissions" are terms that supplement the terms of this
|
||||||
|
License by making exceptions from one or more of its conditions.
|
||||||
|
Additional permissions that are applicable to the entire Program shall
|
||||||
|
be treated as though they were included in this License, to the extent
|
||||||
|
that they are valid under applicable law. If additional permissions
|
||||||
|
apply only to part of the Program, that part may be used separately
|
||||||
|
under those permissions, but the entire Program remains governed by
|
||||||
|
this License without regard to the additional permissions.
|
||||||
|
|
||||||
|
When you convey a copy of a covered work, you may at your option
|
||||||
|
remove any additional permissions from that copy, or from any part of
|
||||||
|
it. (Additional permissions may be written to require their own
|
||||||
|
removal in certain cases when you modify the work.) You may place
|
||||||
|
additional permissions on material, added by you to a covered work,
|
||||||
|
for which you have or can give appropriate copyright permission.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, for material you
|
||||||
|
add to a covered work, you may (if authorized by the copyright holders of
|
||||||
|
that material) supplement the terms of this License with terms:
|
||||||
|
|
||||||
|
a) Disclaiming warranty or limiting liability differently from the
|
||||||
|
terms of sections 15 and 16 of this License; or
|
||||||
|
|
||||||
|
b) Requiring preservation of specified reasonable legal notices or
|
||||||
|
author attributions in that material or in the Appropriate Legal
|
||||||
|
Notices displayed by works containing it; or
|
||||||
|
|
||||||
|
c) Prohibiting misrepresentation of the origin of that material, or
|
||||||
|
requiring that modified versions of such material be marked in
|
||||||
|
reasonable ways as different from the original version; or
|
||||||
|
|
||||||
|
d) Limiting the use for publicity purposes of names of licensors or
|
||||||
|
authors of the material; or
|
||||||
|
|
||||||
|
e) Declining to grant rights under trademark law for use of some
|
||||||
|
trade names, trademarks, or service marks; or
|
||||||
|
|
||||||
|
f) Requiring indemnification of licensors and authors of that
|
||||||
|
material by anyone who conveys the material (or modified versions of
|
||||||
|
it) with contractual assumptions of liability to the recipient, for
|
||||||
|
any liability that these contractual assumptions directly impose on
|
||||||
|
those licensors and authors.
|
||||||
|
|
||||||
|
All other non-permissive additional terms are considered "further
|
||||||
|
restrictions" within the meaning of section 10. If the Program as you
|
||||||
|
received it, or any part of it, contains a notice stating that it is
|
||||||
|
governed by this License along with a term that is a further
|
||||||
|
restriction, you may remove that term. If a license document contains
|
||||||
|
a further restriction but permits relicensing or conveying under this
|
||||||
|
License, you may add to a covered work material governed by the terms
|
||||||
|
of that license document, provided that the further restriction does
|
||||||
|
not survive such relicensing or conveying.
|
||||||
|
|
||||||
|
If you add terms to a covered work in accord with this section, you
|
||||||
|
must place, in the relevant source files, a statement of the
|
||||||
|
additional terms that apply to those files, or a notice indicating
|
||||||
|
where to find the applicable terms.
|
||||||
|
|
||||||
|
Additional terms, permissive or non-permissive, may be stated in the
|
||||||
|
form of a separately written license, or stated as exceptions;
|
||||||
|
the above requirements apply either way.
|
||||||
|
|
||||||
|
8. Termination.
|
||||||
|
|
||||||
|
You may not propagate or modify a covered work except as expressly
|
||||||
|
provided under this License. Any attempt otherwise to propagate or
|
||||||
|
modify it is void, and will automatically terminate your rights under
|
||||||
|
this License (including any patent licenses granted under the third
|
||||||
|
paragraph of section 11).
|
||||||
|
|
||||||
|
However, if you cease all violation of this License, then your
|
||||||
|
license from a particular copyright holder is reinstated (a)
|
||||||
|
provisionally, unless and until the copyright holder explicitly and
|
||||||
|
finally terminates your license, and (b) permanently, if the copyright
|
||||||
|
holder fails to notify you of the violation by some reasonable means
|
||||||
|
prior to 60 days after the cessation.
|
||||||
|
|
||||||
|
Moreover, your license from a particular copyright holder is
|
||||||
|
reinstated permanently if the copyright holder notifies you of the
|
||||||
|
violation by some reasonable means, this is the first time you have
|
||||||
|
received notice of violation of this License (for any work) from that
|
||||||
|
copyright holder, and you cure the violation prior to 30 days after
|
||||||
|
your receipt of the notice.
|
||||||
|
|
||||||
|
Termination of your rights under this section does not terminate the
|
||||||
|
licenses of parties who have received copies or rights from you under
|
||||||
|
this License. If your rights have been terminated and not permanently
|
||||||
|
reinstated, you do not qualify to receive new licenses for the same
|
||||||
|
material under section 10.
|
||||||
|
|
||||||
|
9. Acceptance Not Required for Having Copies.
|
||||||
|
|
||||||
|
You are not required to accept this License in order to receive or
|
||||||
|
run a copy of the Program. Ancillary propagation of a covered work
|
||||||
|
occurring solely as a consequence of using peer-to-peer transmission
|
||||||
|
to receive a copy likewise does not require acceptance. However,
|
||||||
|
nothing other than this License grants you permission to propagate or
|
||||||
|
modify any covered work. These actions infringe copyright if you do
|
||||||
|
not accept this License. Therefore, by modifying or propagating a
|
||||||
|
covered work, you indicate your acceptance of this License to do so.
|
||||||
|
|
||||||
|
10. Automatic Licensing of Downstream Recipients.
|
||||||
|
|
||||||
|
Each time you convey a covered work, the recipient automatically
|
||||||
|
receives a license from the original licensors, to run, modify and
|
||||||
|
propagate that work, subject to this License. You are not responsible
|
||||||
|
for enforcing compliance by third parties with this License.
|
||||||
|
|
||||||
|
An "entity transaction" is a transaction transferring control of an
|
||||||
|
organization, or substantially all assets of one, or subdividing an
|
||||||
|
organization, or merging organizations. If propagation of a covered
|
||||||
|
work results from an entity transaction, each party to that
|
||||||
|
transaction who receives a copy of the work also receives whatever
|
||||||
|
licenses to the work the party's predecessor in interest had or could
|
||||||
|
give under the previous paragraph, plus a right to possession of the
|
||||||
|
Corresponding Source of the work from the predecessor in interest, if
|
||||||
|
the predecessor has it or can get it with reasonable efforts.
|
||||||
|
|
||||||
|
You may not impose any further restrictions on the exercise of the
|
||||||
|
rights granted or affirmed under this License. For example, you may
|
||||||
|
not impose a license fee, royalty, or other charge for exercise of
|
||||||
|
rights granted under this License, and you may not initiate litigation
|
||||||
|
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||||
|
any patent claim is infringed by making, using, selling, offering for
|
||||||
|
sale, or importing the Program or any portion of it.
|
||||||
|
|
||||||
|
11. Patents.
|
||||||
|
|
||||||
|
A "contributor" is a copyright holder who authorizes use under this
|
||||||
|
License of the Program or a work on which the Program is based. The
|
||||||
|
work thus licensed is called the contributor's "contributor version".
|
||||||
|
|
||||||
|
A contributor's "essential patent claims" are all patent claims
|
||||||
|
owned or controlled by the contributor, whether already acquired or
|
||||||
|
hereafter acquired, that would be infringed by some manner, permitted
|
||||||
|
by this License, of making, using, or selling its contributor version,
|
||||||
|
but do not include claims that would be infringed only as a
|
||||||
|
consequence of further modification of the contributor version. For
|
||||||
|
purposes of this definition, "control" includes the right to grant
|
||||||
|
patent sublicenses in a manner consistent with the requirements of
|
||||||
|
this License.
|
||||||
|
|
||||||
|
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||||
|
patent license under the contributor's essential patent claims, to
|
||||||
|
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||||
|
propagate the contents of its contributor version.
|
||||||
|
|
||||||
|
In the following three paragraphs, a "patent license" is any express
|
||||||
|
agreement or commitment, however denominated, not to enforce a patent
|
||||||
|
(such as an express permission to practice a patent or covenant not to
|
||||||
|
sue for patent infringement). To "grant" such a patent license to a
|
||||||
|
party means to make such an agreement or commitment not to enforce a
|
||||||
|
patent against the party.
|
||||||
|
|
||||||
|
If you convey a covered work, knowingly relying on a patent license,
|
||||||
|
and the Corresponding Source of the work is not available for anyone
|
||||||
|
to copy, free of charge and under the terms of this License, through a
|
||||||
|
publicly available network server or other readily accessible means,
|
||||||
|
then you must either (1) cause the Corresponding Source to be so
|
||||||
|
available, or (2) arrange to deprive yourself of the benefit of the
|
||||||
|
patent license for this particular work, or (3) arrange, in a manner
|
||||||
|
consistent with the requirements of this License, to extend the patent
|
||||||
|
license to downstream recipients. "Knowingly relying" means you have
|
||||||
|
actual knowledge that, but for the patent license, your conveying the
|
||||||
|
covered work in a country, or your recipient's use of the covered work
|
||||||
|
in a country, would infringe one or more identifiable patents in that
|
||||||
|
country that you have reason to believe are valid.
|
||||||
|
|
||||||
|
If, pursuant to or in connection with a single transaction or
|
||||||
|
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||||
|
covered work, and grant a patent license to some of the parties
|
||||||
|
receiving the covered work authorizing them to use, propagate, modify
|
||||||
|
or convey a specific copy of the covered work, then the patent license
|
||||||
|
you grant is automatically extended to all recipients of the covered
|
||||||
|
work and works based on it.
|
||||||
|
|
||||||
|
A patent license is "discriminatory" if it does not include within
|
||||||
|
the scope of its coverage, prohibits the exercise of, or is
|
||||||
|
conditioned on the non-exercise of one or more of the rights that are
|
||||||
|
specifically granted under this License. You may not convey a covered
|
||||||
|
work if you are a party to an arrangement with a third party that is
|
||||||
|
in the business of distributing software, under which you make payment
|
||||||
|
to the third party based on the extent of your activity of conveying
|
||||||
|
the work, and under which the third party grants, to any of the
|
||||||
|
parties who would receive the covered work from you, a discriminatory
|
||||||
|
patent license (a) in connection with copies of the covered work
|
||||||
|
conveyed by you (or copies made from those copies), or (b) primarily
|
||||||
|
for and in connection with specific products or compilations that
|
||||||
|
contain the covered work, unless you entered into that arrangement,
|
||||||
|
or that patent license was granted, prior to 28 March 2007.
|
||||||
|
|
||||||
|
Nothing in this License shall be construed as excluding or limiting
|
||||||
|
any implied license or other defenses to infringement that may
|
||||||
|
otherwise be available to you under applicable patent law.
|
||||||
|
|
||||||
|
12. No Surrender of Others' Freedom.
|
||||||
|
|
||||||
|
If conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot convey a
|
||||||
|
covered work so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you may
|
||||||
|
not convey it at all. For example, if you agree to terms that obligate you
|
||||||
|
to collect a royalty for further conveying from those to whom you convey
|
||||||
|
the Program, the only way you could satisfy both those terms and this
|
||||||
|
License would be to refrain entirely from conveying the Program.
|
||||||
|
|
||||||
|
13. Use with the GNU Affero General Public License.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, you have
|
||||||
|
permission to link or combine any covered work with a work licensed
|
||||||
|
under version 3 of the GNU Affero General Public License into a single
|
||||||
|
combined work, and to convey the resulting work. The terms of this
|
||||||
|
License will continue to apply to the part which is the covered work,
|
||||||
|
but the special requirements of the GNU Affero General Public License,
|
||||||
|
section 13, concerning interaction through a network will apply to the
|
||||||
|
combination as such.
|
||||||
|
|
||||||
|
14. Revised Versions of this License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions of
|
||||||
|
the GNU General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the
|
||||||
|
Program specifies that a certain numbered version of the GNU General
|
||||||
|
Public License "or any later version" applies to it, you have the
|
||||||
|
option of following the terms and conditions either of that numbered
|
||||||
|
version or of any later version published by the Free Software
|
||||||
|
Foundation. If the Program does not specify a version number of the
|
||||||
|
GNU General Public License, you may choose any version ever published
|
||||||
|
by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Program specifies that a proxy can decide which future
|
||||||
|
versions of the GNU General Public License can be used, that proxy's
|
||||||
|
public statement of acceptance of a version permanently authorizes you
|
||||||
|
to choose that version for the Program.
|
||||||
|
|
||||||
|
Later license versions may give you additional or different
|
||||||
|
permissions. However, no additional obligations are imposed on any
|
||||||
|
author or copyright holder as a result of your choosing to follow a
|
||||||
|
later version.
|
||||||
|
|
||||||
|
15. Disclaimer of Warranty.
|
||||||
|
|
||||||
|
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||||
|
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||||
|
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||||
|
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||||
|
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||||
|
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
16. Limitation of Liability.
|
||||||
|
|
||||||
|
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||||
|
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||||
|
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||||
|
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||||
|
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||||
|
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||||
|
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||||
|
SUCH DAMAGES.
|
||||||
|
|
||||||
|
17. Interpretation of Sections 15 and 16.
|
||||||
|
|
||||||
|
If the disclaimer of warranty and limitation of liability provided
|
||||||
|
above cannot be given local legal effect according to their terms,
|
||||||
|
reviewing courts shall apply local law that most closely approximates
|
||||||
|
an absolute waiver of all civil liability in connection with the
|
||||||
|
Program, unless a warranty or assumption of liability accompanies a
|
||||||
|
copy of the Program in return for a fee.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
state the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program does terminal interaction, make it output a short
|
||||||
|
notice like this when it starts in an interactive mode:
|
||||||
|
|
||||||
|
<program> Copyright (C) <year> <name of author>
|
||||||
|
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, your program's commands
|
||||||
|
might be different; for a GUI interface, you would use an "about box".
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or school,
|
||||||
|
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||||
|
For more information on this, and how to apply and follow the GNU GPL, see
|
||||||
|
<https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
The GNU General Public License does not permit incorporating your program
|
||||||
|
into proprietary programs. If your program is a subroutine library, you
|
||||||
|
may consider it more useful to permit linking proprietary applications with
|
||||||
|
the library. If this is what you want to do, use the GNU Lesser General
|
||||||
|
Public License instead of this License. But first, please read
|
||||||
|
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
178
Logic.cpp
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
#include "Logic.h"
|
||||||
|
|
||||||
|
#include <QFileDialog>
|
||||||
|
|
||||||
|
#include "eConnectorType.h"
|
||||||
|
#include "Part.h"
|
||||||
|
#include "Connector.h"
|
||||||
|
#include "Wire.h"
|
||||||
|
#include "FileHandler.h"
|
||||||
|
#include "Scene.h"
|
||||||
|
#include "MainWindow.h"
|
||||||
|
|
||||||
|
#include "Parts/BufferGate.h"
|
||||||
|
#include "Parts/NotGate.h"
|
||||||
|
#include "Parts/AndGate.h"
|
||||||
|
#include "Parts/OrGate.h"
|
||||||
|
#include "Parts/NandGate.h"
|
||||||
|
#include "Parts/NorGate.h"
|
||||||
|
#include "Parts/XorGate.h"
|
||||||
|
#include "Parts/XnorGate.h"
|
||||||
|
#include "Parts/HighConstant.h"
|
||||||
|
#include "Parts/LowConstant.h"
|
||||||
|
#include "Parts/LightBulb.h"
|
||||||
|
#include "Parts/ToggleButton.h"
|
||||||
|
#include "Parts/IntegratedCircuit.h"
|
||||||
|
|
||||||
|
Logic::Logic(Scene* parentScene)
|
||||||
|
:m_parentScene(parentScene)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Scene* Logic::parentScene()
|
||||||
|
{
|
||||||
|
return m_parentScene;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logic::doLogicStep()
|
||||||
|
{
|
||||||
|
// The method of first updating the items, then the connections makes everything happen completely
|
||||||
|
// synchronously and makes sure that a signal isn't propagated or computed twice in a single step
|
||||||
|
|
||||||
|
// Let the circuitItems compute everything
|
||||||
|
for(auto part : m_parts)
|
||||||
|
{
|
||||||
|
part->updateState();
|
||||||
|
}
|
||||||
|
// Reset the state of any connector receiving input before each step
|
||||||
|
for(auto connector : m_inputConnectors)
|
||||||
|
{
|
||||||
|
connector->m_state = false;
|
||||||
|
}
|
||||||
|
// Make wires propagate forward their input
|
||||||
|
for(auto wire : m_wires)
|
||||||
|
{
|
||||||
|
wire->feedInput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Logic::saveToFile(QString filename)
|
||||||
|
{
|
||||||
|
if(m_parentScene)
|
||||||
|
m_parentScene->m_parentMainWindow->changesSaved();
|
||||||
|
FileHandler fh(this);
|
||||||
|
return fh.save(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Logic::loadFromFile(QString filename)
|
||||||
|
{
|
||||||
|
FileHandler fh(this);
|
||||||
|
return fh.open(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
// PRIVATE
|
||||||
|
IntegratedCircuit* Logic::createIC(QString filename, QPointF pos)
|
||||||
|
{
|
||||||
|
IntegratedCircuit* ic = new IntegratedCircuit(this, filename);
|
||||||
|
if(m_parentScene)
|
||||||
|
m_parentScene->addItem(ic);
|
||||||
|
m_parts.append(ic);
|
||||||
|
ic->setPos(pos);
|
||||||
|
ic->m_oldPos = pos;
|
||||||
|
ic->m_partType = PartType::IntegratedCircuit;
|
||||||
|
return ic;
|
||||||
|
}
|
||||||
|
|
||||||
|
Part* Logic::createPart(PartType::PartType partType, QPointF pos)
|
||||||
|
{
|
||||||
|
Part *part;
|
||||||
|
|
||||||
|
if(partType == PartType::GateBuffer)
|
||||||
|
part = new BufferGate(this);
|
||||||
|
else if(partType == PartType::GateNot)
|
||||||
|
part = new NotGate(this);
|
||||||
|
else if(partType == PartType::GateAnd)
|
||||||
|
part = new AndGate(this);
|
||||||
|
else if(partType == PartType::GateOr)
|
||||||
|
part = new OrGate(this);
|
||||||
|
else if(partType == PartType::GateNand)
|
||||||
|
part = new NandGate(this);
|
||||||
|
else if(partType == PartType::GateNor)
|
||||||
|
part = new NorGate(this);
|
||||||
|
else if(partType == PartType::GateXor)
|
||||||
|
part = new XorGate(this);
|
||||||
|
else if(partType == PartType::GateXnor)
|
||||||
|
part = new XnorGate(this);
|
||||||
|
else if(partType == PartType::IOHighConstant)
|
||||||
|
part = new HighConstant(this);
|
||||||
|
else if(partType == PartType::IOLowConstant)
|
||||||
|
part = new LowConstant(this);
|
||||||
|
else if(partType == PartType::IOLightBulb)
|
||||||
|
part = new LightBulb(this);
|
||||||
|
else if(partType == PartType::IOToggleButton)
|
||||||
|
part = new ToggleButton(this);
|
||||||
|
|
||||||
|
if(m_parentScene)
|
||||||
|
m_parentScene->addItem(part);
|
||||||
|
m_parts.append(part);
|
||||||
|
part->setPos(pos);
|
||||||
|
part->m_oldPos = pos;
|
||||||
|
part->m_partType = partType;
|
||||||
|
|
||||||
|
return part;
|
||||||
|
}
|
||||||
|
|
||||||
|
Wire* Logic::createWire(Connector *inputConnector, Connector *outputConnector)
|
||||||
|
{
|
||||||
|
Wire* wire = new Wire(m_parentScene, inputConnector, outputConnector);
|
||||||
|
for(auto w : inputConnector->m_wires)
|
||||||
|
{
|
||||||
|
// If the connection already exists, don't add it and return nullptr
|
||||||
|
if((inputConnector->m_connectorType == ConnectorType::Input && w->m_connectorInput == outputConnector) ||
|
||||||
|
(inputConnector->m_connectorType == ConnectorType::Output && w->m_connectorOutput == outputConnector))
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Append wire to connector wire arrays
|
||||||
|
inputConnector->m_wires.append(wire);
|
||||||
|
outputConnector->m_wires.append(wire);
|
||||||
|
// Add wire to scene
|
||||||
|
if(m_parentScene)
|
||||||
|
m_parentScene->addItem(wire);
|
||||||
|
// Add wire to scene's tracker list
|
||||||
|
m_wires.append(wire);
|
||||||
|
|
||||||
|
return wire;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logic::deletePart(Part* part)
|
||||||
|
{
|
||||||
|
// Remove all of the part's connections first
|
||||||
|
for(auto input : part->m_inputs)
|
||||||
|
{
|
||||||
|
for(auto wire : input->m_wires)
|
||||||
|
deleteWire(wire);
|
||||||
|
}
|
||||||
|
for(auto output : part->m_outputs)
|
||||||
|
{
|
||||||
|
for(auto wire : output->m_wires)
|
||||||
|
deleteWire(wire);
|
||||||
|
}
|
||||||
|
// Remove part out of Logic's tracking list
|
||||||
|
m_parts.removeOne(part);
|
||||||
|
// Deallocate part
|
||||||
|
delete part;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logic::deleteWire(Wire *wire)
|
||||||
|
{
|
||||||
|
// Remove wire out of Logic's tracking list
|
||||||
|
m_wires.removeOne(wire);
|
||||||
|
// Remove wire out of connectors
|
||||||
|
wire->m_connectorInput->m_wires.removeOne(wire);
|
||||||
|
wire->m_connectorOutput->m_wires.removeOne(wire);
|
||||||
|
// Deallocate wire
|
||||||
|
delete wire;
|
||||||
|
}
|
66
Logic.h
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
#ifndef LOGIC_H
|
||||||
|
#define LOGIC_H
|
||||||
|
|
||||||
|
// This class has everything nescessary to load, save and step through a circuit.
|
||||||
|
// It does not handle anything graphical or related to undo/redo functionality
|
||||||
|
|
||||||
|
#include <QList>
|
||||||
|
#include <QPointF>
|
||||||
|
#include "ePartType.h"
|
||||||
|
|
||||||
|
class Part;
|
||||||
|
class Wire;
|
||||||
|
class Connector;
|
||||||
|
class Scene;
|
||||||
|
class IntegratedCircuit;
|
||||||
|
|
||||||
|
class Logic
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
friend class Scene;
|
||||||
|
friend class FileHandler;
|
||||||
|
friend class Part;
|
||||||
|
|
||||||
|
friend class AddPart;
|
||||||
|
friend class RemoveParts;
|
||||||
|
friend class AddWire;
|
||||||
|
friend class RemoveWire;
|
||||||
|
friend class CopyParts;
|
||||||
|
|
||||||
|
friend class CircuitBuffer;
|
||||||
|
|
||||||
|
friend class IntegratedCircuit;
|
||||||
|
|
||||||
|
Logic(Scene* parentScene = nullptr);
|
||||||
|
|
||||||
|
Scene* parentScene();
|
||||||
|
|
||||||
|
void doLogicStep();
|
||||||
|
|
||||||
|
bool saveToFile(QString filenname);
|
||||||
|
bool loadFromFile(QString filenname);
|
||||||
|
|
||||||
|
// Not undoable
|
||||||
|
IntegratedCircuit* createIC(QString filename, QPointF pos);
|
||||||
|
// Not undoable
|
||||||
|
Part* createPart(PartType::PartType partType, QPointF pos);
|
||||||
|
// Not undoable
|
||||||
|
Wire* createWire(Connector *inputConnector, Connector *outputConnector);
|
||||||
|
|
||||||
|
// Not undoable
|
||||||
|
void deletePart(Part* part);
|
||||||
|
// Not undoable
|
||||||
|
void deleteWire(Wire *wire);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// May be nullptr if there is no parent Scene and this class is purely used for logic
|
||||||
|
Scene* m_parentScene;
|
||||||
|
|
||||||
|
QList<Part*> m_parts;
|
||||||
|
QList<Wire*> m_wires;
|
||||||
|
QList<Connector*> m_inputConnectors;
|
||||||
|
QList<Connector*> m_outputConnectors;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // LOGIC_H
|
512
MainWindow.cpp
Normal file
@ -0,0 +1,512 @@
|
|||||||
|
#include "MainWindow.h"
|
||||||
|
#include "ui_MainWindow.h"
|
||||||
|
|
||||||
|
#include <QGraphicsRectItem>
|
||||||
|
#include <QtMath>
|
||||||
|
#include <QScrollBar>
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QCloseEvent>
|
||||||
|
#include <QDir>
|
||||||
|
|
||||||
|
#include "Connector.h"
|
||||||
|
#include "Connector.h"
|
||||||
|
#include "Wire.h"
|
||||||
|
#include "Part.h"
|
||||||
|
#include "Scene.h"
|
||||||
|
#include "Logic.h"
|
||||||
|
|
||||||
|
#include "UndoCommands/CopyParts.h"
|
||||||
|
|
||||||
|
MainWindow::MainWindow(QWidget *parent, QString loadFile)
|
||||||
|
: QMainWindow(parent)
|
||||||
|
, ui(new Ui::MainWindow)
|
||||||
|
{
|
||||||
|
// Setup UI
|
||||||
|
ui->setupUi(this);
|
||||||
|
// Add tab widget to tool bar to make it moveable and floatable
|
||||||
|
// TODO: Use a less hacky solution and make it work horizontally as well
|
||||||
|
ui->toolBarBottom->addWidget(ui->tabWidget);
|
||||||
|
// Set title name
|
||||||
|
m_title = "Circuit Simulator";
|
||||||
|
// Set initial window title
|
||||||
|
setWindowTitle(m_title + " - Unsaved Circuit");
|
||||||
|
// Initialize graphics scene
|
||||||
|
m_scene = new Scene(ui->graphicsView, this);
|
||||||
|
if(!loadFile.isEmpty())
|
||||||
|
{
|
||||||
|
m_currFilename = loadFile;
|
||||||
|
m_fileLoaded = true;
|
||||||
|
if(!m_scene->m_logic->loadFromFile(loadFile))
|
||||||
|
{
|
||||||
|
m_fileLoaded = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
setWindowTitle(m_title + " - " + QFileInfo(m_currFilename).fileName());
|
||||||
|
}
|
||||||
|
// Set active tool mode to select
|
||||||
|
toolSelect();
|
||||||
|
// Set active mode to sim started
|
||||||
|
simStart();
|
||||||
|
// Assign scene to graphics view and show it
|
||||||
|
ui->graphicsView->setScene(m_scene);
|
||||||
|
ui->graphicsView->show();
|
||||||
|
// Setup undoView
|
||||||
|
undoView = new QUndoView(m_scene->m_undoStack);
|
||||||
|
undoView->setWindowTitle("Undo View");
|
||||||
|
undoView->setAttribute(Qt::WA_QuitOnClose, false);
|
||||||
|
// Setup graphics timer
|
||||||
|
QTimer *gfxTimer = new QTimer(this);
|
||||||
|
connect(gfxTimer, &QTimer::timeout, this, &MainWindow::onGfxTimerTimeout);
|
||||||
|
gfxTimer->start(17);
|
||||||
|
// Setup logic timer
|
||||||
|
QTimer *logicTimer = new QTimer(this);
|
||||||
|
connect(logicTimer, &QTimer::timeout, this, &MainWindow::onLogicTimerTimeout);
|
||||||
|
logicTimer->start(1);
|
||||||
|
// Refresh IC list
|
||||||
|
reloadLocalICs();
|
||||||
|
//CONNECT EVENTS
|
||||||
|
connect(ui->zoomSlider, &QSlider::valueChanged, this, &MainWindow::updateMatrix);
|
||||||
|
|
||||||
|
connect(ui->btnZoomIn, &QToolButton::clicked, this, &MainWindow::zoomIn);
|
||||||
|
connect(ui->btnZoomOut, &QToolButton::clicked, this, &MainWindow::zoomOut);
|
||||||
|
|
||||||
|
connect(ui->actionZoom_In, &QAction::triggered, this, &MainWindow::zoomIn);
|
||||||
|
connect(ui->actionZoom_Out, &QAction::triggered, this, &MainWindow::zoomOut);
|
||||||
|
connect(ui->actionReset_Zoom, &QAction::triggered, this, &MainWindow::resetZoom);
|
||||||
|
|
||||||
|
connect(ui->actionToggle_Undo_View, &QAction::triggered, this, &MainWindow::toggleUndoView);
|
||||||
|
|
||||||
|
connect(ui->actionUndo, &QAction::triggered, this, &MainWindow::editUndo);
|
||||||
|
connect(ui->actionRedo, &QAction::triggered, this, &MainWindow::editRedo);
|
||||||
|
connect(ui->actionCut, &QAction::triggered, this, &MainWindow::editCut);
|
||||||
|
connect(ui->actionCopy, &QAction::triggered, this, &MainWindow::editCopy);
|
||||||
|
connect(ui->actionPaste, &QAction::triggered, this, &MainWindow::editPaste);
|
||||||
|
connect(ui->actionDelete, &QAction::triggered, this, &MainWindow::editDelete);
|
||||||
|
|
||||||
|
connect(ui->actionNew, &QAction::triggered, this, &MainWindow::fileNew);
|
||||||
|
connect(ui->actionOpen, &QAction::triggered, this, &MainWindow::fileOpen);
|
||||||
|
connect(ui->actionSave, &QAction::triggered, this, &MainWindow::fileSave);
|
||||||
|
connect(ui->actionSave_As, &QAction::triggered, this, &MainWindow::fileSaveAs);
|
||||||
|
connect(ui->actionExit, &QAction::triggered, this, &MainWindow::fileExit);
|
||||||
|
|
||||||
|
connect(ui->actionConnect, &QAction::triggered, this, &MainWindow::toolConnect);
|
||||||
|
connect(ui->actionRemove_Connections, &QAction::triggered, this, &MainWindow::toolDisconnect);
|
||||||
|
connect(ui->actionSelect, &QAction::triggered, this, &MainWindow::toolSelect);
|
||||||
|
connect(ui->actionPan, &QAction::triggered, this, &MainWindow::toolPan);
|
||||||
|
|
||||||
|
connect(ui->actionStep, &QAction::triggered, this, &MainWindow::simStep);
|
||||||
|
connect(ui->actionStart, &QAction::triggered, this, &MainWindow::simStart);
|
||||||
|
connect(ui->actionStop, &QAction::triggered, this, &MainWindow::simStop);
|
||||||
|
|
||||||
|
connect(ui->btnGateBuffer, &QToolButton::clicked, this, &MainWindow::toolAddComponent);
|
||||||
|
connect(ui->btnGateNot, &QToolButton::clicked, this, &MainWindow::toolAddComponent);
|
||||||
|
connect(ui->btnGateAnd, &QToolButton::clicked, this, &MainWindow::toolAddComponent);
|
||||||
|
connect(ui->btnGateOr, &QToolButton::clicked, this, &MainWindow::toolAddComponent);
|
||||||
|
connect(ui->btnGateNand, &QToolButton::clicked, this, &MainWindow::toolAddComponent);
|
||||||
|
connect(ui->btnGateNor, &QToolButton::clicked, this, &MainWindow::toolAddComponent);
|
||||||
|
connect(ui->btnGateXor, &QToolButton::clicked, this, &MainWindow::toolAddComponent);
|
||||||
|
connect(ui->btnGateXnor, &QToolButton::clicked, this, &MainWindow::toolAddComponent);
|
||||||
|
|
||||||
|
connect(ui->btnIOHighConstant, &QToolButton::clicked, this, &MainWindow::toolAddComponent);
|
||||||
|
connect(ui->btnIOLowConstant, &QToolButton::clicked, this, &MainWindow::toolAddComponent);
|
||||||
|
connect(ui->btnIOLightBulb, &QToolButton::clicked, this, &MainWindow::toolAddComponent);
|
||||||
|
connect(ui->btnIOToggleButton, &QToolButton::clicked, this, &MainWindow::toolAddComponent);
|
||||||
|
//END CONNECT EVENTS
|
||||||
|
}
|
||||||
|
|
||||||
|
MainWindow::~MainWindow()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MainWindow::isFileLoaded()
|
||||||
|
{
|
||||||
|
return m_fileLoaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString MainWindow::currFilename()
|
||||||
|
{
|
||||||
|
return m_currFilename;
|
||||||
|
}
|
||||||
|
|
||||||
|
//PUBLIC
|
||||||
|
|
||||||
|
void MainWindow::resetTools()
|
||||||
|
{
|
||||||
|
// Reset button checked states
|
||||||
|
ui->actionConnect->setChecked(false);
|
||||||
|
ui->actionRemove_Connections->setChecked(false);
|
||||||
|
ui->actionSelect->setChecked(false);
|
||||||
|
ui->actionPan->setChecked(false);
|
||||||
|
// Reset drag mode
|
||||||
|
ui->graphicsView->setDragMode(QGraphicsView::NoDrag);
|
||||||
|
// Unselect selected items
|
||||||
|
for(auto item : m_scene->selectedItems())
|
||||||
|
item->setSelected(false);
|
||||||
|
// Reset graphicsView interactivity
|
||||||
|
ui->graphicsView->setInteractive(true);
|
||||||
|
//Reset cursor shape
|
||||||
|
ui->graphicsView->setCursor(QCursor(Qt::CursorShape::ArrowCursor));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::changeMade()
|
||||||
|
{
|
||||||
|
unsavedChanges = true;
|
||||||
|
if(m_fileLoaded)
|
||||||
|
setWindowTitle(m_title + " - " + QFileInfo(m_currFilename).fileName() + "*");
|
||||||
|
else
|
||||||
|
setWindowTitle(m_title + " - Unsaved Circuit*");
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::changesSaved()
|
||||||
|
{
|
||||||
|
unsavedChanges = false;
|
||||||
|
setWindowTitle(m_title + " - " + QFileInfo(m_currFilename).fileName());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::closeEvent(QCloseEvent *event)
|
||||||
|
{
|
||||||
|
if(!unsavedChanges)
|
||||||
|
{
|
||||||
|
event->accept();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// I just blatantly ripped off the following code from this example https://doc.qt.io/qt-5/qmessagebox.html
|
||||||
|
QMessageBox msgBox;
|
||||||
|
msgBox.setText("The Circuit has unsaved changes.");
|
||||||
|
msgBox.setInformativeText("Do you really want to quit?");
|
||||||
|
msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
|
||||||
|
msgBox.setDefaultButton(QMessageBox::Save);
|
||||||
|
int ret = msgBox.exec();
|
||||||
|
|
||||||
|
switch (ret)
|
||||||
|
{
|
||||||
|
case QMessageBox::Save:
|
||||||
|
fileSave();
|
||||||
|
if(!unsavedChanges)
|
||||||
|
event->accept();
|
||||||
|
event->ignore();
|
||||||
|
break;
|
||||||
|
case QMessageBox::Discard:
|
||||||
|
event->accept();
|
||||||
|
break;
|
||||||
|
case QMessageBox::Cancel:
|
||||||
|
event->ignore();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::reloadLocalICs()
|
||||||
|
{
|
||||||
|
// Return if no file is loaded
|
||||||
|
if(!m_fileLoaded)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(tabICInfoLabelExists)
|
||||||
|
{
|
||||||
|
delete ui->tabICInfoLabel;
|
||||||
|
tabICInfoLabelExists = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto btn : m_icPushButtons)
|
||||||
|
{
|
||||||
|
delete btn;
|
||||||
|
}
|
||||||
|
m_icPushButtons.clear();
|
||||||
|
|
||||||
|
QDir fileDir(m_currFilename);
|
||||||
|
fileDir.cdUp();
|
||||||
|
QStringList nameFilter("*.csim");
|
||||||
|
QStringList icFiles = fileDir.entryList(nameFilter, QDir::Files);
|
||||||
|
|
||||||
|
for(const auto& icFile : icFiles)
|
||||||
|
{
|
||||||
|
// Skip step if file name is equal to currently loaded file
|
||||||
|
if(icFile == QFileInfo(m_currFilename).fileName())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
QPushButton* btn = new QPushButton(ui->tabICScrollAreaWidgetContents);
|
||||||
|
|
||||||
|
ui->tabICScrollAreaWidgetContents->layout()->addWidget(btn);
|
||||||
|
btn->setText(icFile);
|
||||||
|
btn->setObjectName(icFile);
|
||||||
|
btn->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
|
||||||
|
m_icPushButtons.append(btn);
|
||||||
|
|
||||||
|
connect(btn, &QPushButton::clicked, this, &MainWindow::toolAddIC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//SIGNALS
|
||||||
|
void MainWindow::updateMatrix()
|
||||||
|
{
|
||||||
|
qreal scale = qPow(qreal(2), qreal(ui->zoomSlider->value() - 100) / qreal(20));
|
||||||
|
|
||||||
|
ui->labelZoomLevel->setText(QString::number(int(scale * 100.0)) + '%');
|
||||||
|
|
||||||
|
QMatrix matrix;
|
||||||
|
matrix.scale(scale, scale);
|
||||||
|
ui->graphicsView->setMatrix(matrix);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::zoomIn()
|
||||||
|
{
|
||||||
|
ui->zoomSlider->setValue(ui->zoomSlider->value() + ui->zoomSlider->pageStep());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::zoomOut()
|
||||||
|
{
|
||||||
|
ui->zoomSlider->setValue(ui->zoomSlider->value() - ui->zoomSlider->pageStep());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::resetZoom()
|
||||||
|
{
|
||||||
|
ui->zoomSlider->setValue(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::toggleUndoView()
|
||||||
|
{
|
||||||
|
if(undoView->isHidden())
|
||||||
|
undoView->show();
|
||||||
|
else
|
||||||
|
undoView->hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::editUndo()
|
||||||
|
{
|
||||||
|
m_scene->undo();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::editRedo()
|
||||||
|
{
|
||||||
|
m_scene->redo();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::editCut()
|
||||||
|
{
|
||||||
|
// Put parts into copy buffer
|
||||||
|
editCopy();
|
||||||
|
// Remove selected parts
|
||||||
|
QList<QGraphicsItem*> selItems = m_scene->selectedItems();
|
||||||
|
QList<Part*> selParts;
|
||||||
|
for(auto convItm : selItems)
|
||||||
|
selParts.append((Part*)convItm);
|
||||||
|
m_scene->removeParts(selParts);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::editCopy()
|
||||||
|
{
|
||||||
|
QList<QGraphicsItem*> selItems = m_scene->selectedItems();
|
||||||
|
QSet<Part*> selParts;
|
||||||
|
QList<Part*> selPartsList;
|
||||||
|
QList<Wire*> selPartsWires;
|
||||||
|
|
||||||
|
for(auto item : selItems)
|
||||||
|
selParts.insert((Part*)item);
|
||||||
|
|
||||||
|
selPartsList = selParts.values();
|
||||||
|
|
||||||
|
// Problem: find all wires of which both sides are being used by selected parts
|
||||||
|
// Go through all selected parts
|
||||||
|
for(auto part : selPartsList)
|
||||||
|
{
|
||||||
|
// Go through their outgoing connectors
|
||||||
|
for(auto outConnector : part->m_outputs)
|
||||||
|
{
|
||||||
|
// Go through their wires
|
||||||
|
for(auto outWire : outConnector->m_wires)
|
||||||
|
{
|
||||||
|
// See if the other end of the wire contains a part which is also selected
|
||||||
|
if(selParts.contains((Part*)outWire->m_connectorOutput->parentItem()))
|
||||||
|
selPartsWires.append(outWire);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_scene->initCopy(selPartsList, selPartsWires);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::editPaste()
|
||||||
|
{
|
||||||
|
// Only do copy relative to mouse if graphicsView under mouse
|
||||||
|
// Else, copy into center of graphics view
|
||||||
|
m_scene->doCopy(ui->graphicsView->underMouse());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::editDelete()
|
||||||
|
{
|
||||||
|
QList<QGraphicsItem*> selItems = m_scene->selectedItems();
|
||||||
|
QList<Part*> selParts;
|
||||||
|
for(auto convItm : selItems)
|
||||||
|
selParts.append((Part*)convItm);
|
||||||
|
m_scene->removeParts(selParts);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::fileNew()
|
||||||
|
{
|
||||||
|
MainWindow* newWindow = new MainWindow();
|
||||||
|
newWindow->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::fileOpen()
|
||||||
|
{
|
||||||
|
QString filter = tr("CSIM Files(*.csim)");
|
||||||
|
auto filename = QFileDialog::getOpenFileName(this, tr("Open File"), "", filter, &filter);
|
||||||
|
if(!filename.isEmpty())
|
||||||
|
{
|
||||||
|
// If there is already a file loaded or there are unsaved changes, create a new window
|
||||||
|
if(m_fileLoaded || unsavedChanges)
|
||||||
|
{
|
||||||
|
MainWindow* newWindow = new MainWindow(nullptr, filename);
|
||||||
|
newWindow->show();
|
||||||
|
}
|
||||||
|
// Else, load file into current window
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(m_scene->m_logic->loadFromFile(filename))
|
||||||
|
{
|
||||||
|
m_currFilename = filename;
|
||||||
|
m_fileLoaded = true;
|
||||||
|
setWindowTitle(m_title + " - " + QFileInfo(m_currFilename).fileName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reloadLocalICs();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::fileSave()
|
||||||
|
{
|
||||||
|
if(m_fileLoaded)
|
||||||
|
m_scene->m_logic->saveToFile(m_currFilename);
|
||||||
|
else
|
||||||
|
fileSaveAs();
|
||||||
|
reloadLocalICs();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::fileSaveAs()
|
||||||
|
{
|
||||||
|
QString filter = tr("CSIM Files(*.csim)");
|
||||||
|
auto filename = QFileDialog::getSaveFileName(this, tr("Save As"), "", filter, &filter);
|
||||||
|
if(!filename.isEmpty())
|
||||||
|
{
|
||||||
|
if(m_scene->m_logic->saveToFile(filename))
|
||||||
|
{
|
||||||
|
m_fileLoaded = true;
|
||||||
|
m_currFilename = filename;
|
||||||
|
setWindowTitle("Circuit Simulator - " + QFileInfo(m_currFilename).fileName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reloadLocalICs();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::fileExit()
|
||||||
|
{
|
||||||
|
this->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::toolConnect()
|
||||||
|
{
|
||||||
|
resetTools();
|
||||||
|
toolMode = Connect;
|
||||||
|
ui->actionConnect->setChecked(true);
|
||||||
|
ui->graphicsView->setCursor(QCursor(Qt::CursorShape::PointingHandCursor));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::toolDisconnect()
|
||||||
|
{
|
||||||
|
resetTools();
|
||||||
|
toolMode = Disconnect;
|
||||||
|
ui->actionRemove_Connections->setChecked(true);
|
||||||
|
ui->graphicsView->setCursor(QCursor(Qt::CursorShape::PointingHandCursor));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::toolSelect()
|
||||||
|
{
|
||||||
|
resetTools();
|
||||||
|
toolMode = Select;
|
||||||
|
ui->graphicsView->setDragMode(QGraphicsView::RubberBandDrag);
|
||||||
|
ui->actionSelect->setChecked(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::toolPan()
|
||||||
|
{
|
||||||
|
resetTools();
|
||||||
|
toolMode = Pan;
|
||||||
|
ui->graphicsView->setDragMode(QGraphicsView::ScrollHandDrag);
|
||||||
|
ui->graphicsView->setInteractive(false);
|
||||||
|
ui->actionPan->setChecked(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::toolAddComponent()
|
||||||
|
{
|
||||||
|
QToolButton *button = (QToolButton*)sender();
|
||||||
|
|
||||||
|
if(button->objectName() == "btnGateBuffer")
|
||||||
|
m_scene->addPart(PartType::GateBuffer);
|
||||||
|
else if(button->objectName() == "btnGateNot")
|
||||||
|
m_scene->addPart(PartType::GateNot);
|
||||||
|
else if(button->objectName() == "btnGateAnd")
|
||||||
|
m_scene->addPart(PartType::GateAnd);
|
||||||
|
else if(button->objectName() == "btnGateOr")
|
||||||
|
m_scene->addPart(PartType::GateOr);
|
||||||
|
else if(button->objectName() == "btnGateNand")
|
||||||
|
m_scene->addPart(PartType::GateNand);
|
||||||
|
else if(button->objectName() == "btnGateNor")
|
||||||
|
m_scene->addPart(PartType::GateNor);
|
||||||
|
else if(button->objectName() == "btnGateXor")
|
||||||
|
m_scene->addPart(PartType::GateXor);
|
||||||
|
else if(button->objectName() == "btnGateXnor")
|
||||||
|
m_scene->addPart(PartType::GateXnor);
|
||||||
|
else if(button->objectName() == "btnIOHighConstant")
|
||||||
|
m_scene->addPart(PartType::IOHighConstant);
|
||||||
|
else if(button->objectName() == "btnIOLowConstant")
|
||||||
|
m_scene->addPart(PartType::IOLowConstant);
|
||||||
|
else if(button->objectName() == "btnIOLightBulb")
|
||||||
|
m_scene->addPart(PartType::IOLightBulb);
|
||||||
|
else if(button->objectName() == "btnIOToggleButton")
|
||||||
|
m_scene->addPart(PartType::IOToggleButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::simStep()
|
||||||
|
{
|
||||||
|
m_scene->m_logic->doLogicStep();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::simStart()
|
||||||
|
{
|
||||||
|
ui->actionStart->setEnabled(false);
|
||||||
|
ui->actionStep->setEnabled(false);
|
||||||
|
ui->actionStop->setEnabled(true);
|
||||||
|
simRunning = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::simStop()
|
||||||
|
{
|
||||||
|
ui->actionStart->setEnabled(true);
|
||||||
|
ui->actionStep->setEnabled(true);
|
||||||
|
ui->actionStop->setEnabled(false);
|
||||||
|
simRunning = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::onLogicTimerTimeout()
|
||||||
|
{
|
||||||
|
if(simRunning)
|
||||||
|
m_scene->m_logic->doLogicStep();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::onGfxTimerTimeout()
|
||||||
|
{
|
||||||
|
m_scene->updateGraphics();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::toolAddIC()
|
||||||
|
{
|
||||||
|
QDir fileDir(m_currFilename);
|
||||||
|
fileDir.cdUp();
|
||||||
|
QString path = fileDir.absoluteFilePath(sender()->objectName());
|
||||||
|
m_scene->addIC(path);
|
||||||
|
}
|
||||||
|
//END SIGNALS
|
113
MainWindow.h
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
#ifndef MAINWINDOW_H
|
||||||
|
#define MAINWINDOW_H
|
||||||
|
|
||||||
|
#include <QMainWindow>
|
||||||
|
#include <QGraphicsScene>
|
||||||
|
#include <QToolButton>
|
||||||
|
#include <QUndoStack>
|
||||||
|
#include <QUndoView>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include "eConnectorType.h"
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
namespace Ui { class MainWindow; }
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
class Connector;
|
||||||
|
class Part;
|
||||||
|
class Wire;
|
||||||
|
class Scene;
|
||||||
|
|
||||||
|
class MainWindow : public QMainWindow
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
friend class Part;
|
||||||
|
friend class Logic;
|
||||||
|
friend class Scene;
|
||||||
|
|
||||||
|
enum ToolMode
|
||||||
|
{
|
||||||
|
Connect,
|
||||||
|
Disconnect,
|
||||||
|
Select,
|
||||||
|
Pan
|
||||||
|
};
|
||||||
|
|
||||||
|
MainWindow(QWidget *parent = nullptr, QString loadFile = "");
|
||||||
|
~MainWindow();
|
||||||
|
|
||||||
|
QString currFilename();
|
||||||
|
bool isFileLoaded();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::MainWindow *ui;
|
||||||
|
|
||||||
|
Scene* m_scene;
|
||||||
|
ToolMode toolMode;
|
||||||
|
QToolButton *selTool;
|
||||||
|
|
||||||
|
bool simRunning = false;
|
||||||
|
|
||||||
|
QUndoView *undoView;
|
||||||
|
|
||||||
|
bool m_fileLoaded = false;
|
||||||
|
QString m_title;
|
||||||
|
QString m_currFilename;
|
||||||
|
|
||||||
|
QVector<QPushButton*> m_icPushButtons;
|
||||||
|
|
||||||
|
// True if unsaved changes have been made to the file
|
||||||
|
bool unsavedChanges = false;
|
||||||
|
|
||||||
|
// Label seen in the "Integrated Circuits" tab
|
||||||
|
bool tabICInfoLabelExists = true;
|
||||||
|
|
||||||
|
void resetTools();
|
||||||
|
|
||||||
|
void changeMade();
|
||||||
|
void changesSaved();
|
||||||
|
|
||||||
|
void closeEvent(QCloseEvent *event) override;
|
||||||
|
|
||||||
|
void reloadLocalICs();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void updateMatrix();
|
||||||
|
|
||||||
|
void zoomIn();
|
||||||
|
void zoomOut();
|
||||||
|
void resetZoom();
|
||||||
|
void toggleUndoView();
|
||||||
|
|
||||||
|
void editUndo();
|
||||||
|
void editRedo();
|
||||||
|
void editCut();
|
||||||
|
void editCopy();
|
||||||
|
void editPaste();
|
||||||
|
void editDelete();
|
||||||
|
|
||||||
|
void fileNew();
|
||||||
|
void fileOpen();
|
||||||
|
void fileSave();
|
||||||
|
void fileSaveAs();
|
||||||
|
void fileExit();
|
||||||
|
|
||||||
|
void toolConnect();
|
||||||
|
void toolDisconnect();
|
||||||
|
void toolSelect();
|
||||||
|
void toolPan();
|
||||||
|
|
||||||
|
void toolAddComponent();
|
||||||
|
void toolAddIC();
|
||||||
|
|
||||||
|
|
||||||
|
void simStep();
|
||||||
|
void simStart();
|
||||||
|
void simStop();
|
||||||
|
|
||||||
|
void onLogicTimerTimeout();
|
||||||
|
void onGfxTimerTimeout();
|
||||||
|
};
|
||||||
|
#endif // MAINWINDOW_H
|
833
MainWindow.ui
Normal file
@ -0,0 +1,833 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>MainWindow</class>
|
||||||
|
<widget class="QMainWindow" name="MainWindow">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>884</width>
|
||||||
|
<height>611</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>MainWindow</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="centralwidget">
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="1" column="0" colspan="2">
|
||||||
|
<widget class="QTabWidget" name="tabWidget">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Maximum">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="tabLogicGates">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Logic Gates</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="btnGateBuffer">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Buffer Gate</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>...</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="Resources.qrc">
|
||||||
|
<normaloff>:/Icons/Resources/BUFFER.png</normaloff>:/Icons/Resources/BUFFER.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>64</width>
|
||||||
|
<height>32</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="btnGateNot">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Not Gate</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>...</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="Resources.qrc">
|
||||||
|
<normaloff>:/Icons/Resources/NOT.png</normaloff>:/Icons/Resources/NOT.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>64</width>
|
||||||
|
<height>32</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="btnGateAnd">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>And Gate</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>...</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="Resources.qrc">
|
||||||
|
<normaloff>:/Icons/Resources/AND.png</normaloff>:/Icons/Resources/AND.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>64</width>
|
||||||
|
<height>32</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="btnGateOr">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Or Gate</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>...</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="Resources.qrc">
|
||||||
|
<normaloff>:/Icons/Resources/OR.png</normaloff>:/Icons/Resources/OR.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>64</width>
|
||||||
|
<height>32</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="btnGateNand">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Nand Gate</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>...</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="Resources.qrc">
|
||||||
|
<normaloff>:/Icons/Resources/NAND.png</normaloff>:/Icons/Resources/NAND.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>64</width>
|
||||||
|
<height>32</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="btnGateNor">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Nor Gate</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>...</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="Resources.qrc">
|
||||||
|
<normaloff>:/Icons/Resources/NOR.png</normaloff>:/Icons/Resources/NOR.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>64</width>
|
||||||
|
<height>32</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="btnGateXor">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Xor Gate</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>...</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="Resources.qrc">
|
||||||
|
<normaloff>:/Icons/Resources/XOR.png</normaloff>:/Icons/Resources/XOR.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>64</width>
|
||||||
|
<height>32</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="btnGateXnor">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Xnor Gate</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>...</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="Resources.qrc">
|
||||||
|
<normaloff>:/Icons/Resources/XNOR.png</normaloff>:/Icons/Resources/XNOR.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>64</width>
|
||||||
|
<height>32</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="tabInputOutput">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Input/Output</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="btnIOLowConstant">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Low Constant</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="btnIOHighConstant">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>High Constant</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>...</string>
|
||||||
|
</property>
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>64</width>
|
||||||
|
<height>32</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="btnIOToggleButton">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Toggle Button</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>...</string>
|
||||||
|
</property>
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>64</width>
|
||||||
|
<height>64</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="btnIOLightBulb">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Light Bulb</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>...</string>
|
||||||
|
</property>
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>64</width>
|
||||||
|
<height>32</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="spacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="tabIntegratedCircuits">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Integrated Circuits</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||||
|
<item>
|
||||||
|
<widget class="QScrollArea" name="tabICScrollArea">
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::NoFrame</enum>
|
||||||
|
</property>
|
||||||
|
<property name="widgetResizable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="tabICScrollAreaWidgetContents">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>844</width>
|
||||||
|
<height>64</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="tabICInfoLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>This tab allows you to import .csim files from the directory the file is saved in. To use integrated circuits, please save or open another file.</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QGraphicsView" name="graphicsView">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QGroupBox" name="groupBox">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="title">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="labelZoomLevel">
|
||||||
|
<property name="text">
|
||||||
|
<string>100%</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="btnZoomIn">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Zoom In</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>...</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="zoom-in">
|
||||||
|
<normaloff>.</normaloff>.</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSlider" name="zoomSlider">
|
||||||
|
<property name="maximum">
|
||||||
|
<number>200</number>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>100</number>
|
||||||
|
</property>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="tickPosition">
|
||||||
|
<enum>QSlider::TicksBelow</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="btnZoomOut">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Zoom Out</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>...</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="zoom-out">
|
||||||
|
<normaloff>.</normaloff>.</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenuBar" name="menubar">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>884</width>
|
||||||
|
<height>23</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<widget class="QMenu" name="menuFile">
|
||||||
|
<property name="title">
|
||||||
|
<string>File</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionNew"/>
|
||||||
|
<addaction name="actionOpen"/>
|
||||||
|
<addaction name="actionSave"/>
|
||||||
|
<addaction name="actionSave_As"/>
|
||||||
|
<addaction name="actionExit"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menuTools">
|
||||||
|
<property name="title">
|
||||||
|
<string>Tools</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionConnect"/>
|
||||||
|
<addaction name="actionRemove_Connections"/>
|
||||||
|
<addaction name="actionSelect"/>
|
||||||
|
<addaction name="actionPan"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menuView">
|
||||||
|
<property name="title">
|
||||||
|
<string>View</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionZoom_In"/>
|
||||||
|
<addaction name="actionZoom_Out"/>
|
||||||
|
<addaction name="actionReset_Zoom"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionToggle_Undo_View"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menuEdit">
|
||||||
|
<property name="title">
|
||||||
|
<string>Edit</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionUndo"/>
|
||||||
|
<addaction name="actionRedo"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionCut"/>
|
||||||
|
<addaction name="actionCopy"/>
|
||||||
|
<addaction name="actionPaste"/>
|
||||||
|
<addaction name="actionDelete"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menuSimulation">
|
||||||
|
<property name="title">
|
||||||
|
<string>Simulation</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionStart"/>
|
||||||
|
<addaction name="actionStop"/>
|
||||||
|
<addaction name="actionStep"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menuHelp">
|
||||||
|
<property name="title">
|
||||||
|
<string>Help</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionTutorial"/>
|
||||||
|
<addaction name="actionAbout"/>
|
||||||
|
</widget>
|
||||||
|
<addaction name="menuFile"/>
|
||||||
|
<addaction name="menuEdit"/>
|
||||||
|
<addaction name="menuView"/>
|
||||||
|
<addaction name="menuTools"/>
|
||||||
|
<addaction name="menuSimulation"/>
|
||||||
|
<addaction name="menuHelp"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QToolBar" name="toolBarTop">
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>toolBar</string>
|
||||||
|
</property>
|
||||||
|
<property name="movable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="floatable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<attribute name="toolBarArea">
|
||||||
|
<enum>TopToolBarArea</enum>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="toolBarBreak">
|
||||||
|
<bool>false</bool>
|
||||||
|
</attribute>
|
||||||
|
<addaction name="actionNew"/>
|
||||||
|
<addaction name="actionOpen"/>
|
||||||
|
<addaction name="actionSave"/>
|
||||||
|
<addaction name="actionSave_As"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionUndo"/>
|
||||||
|
<addaction name="actionRedo"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionCut"/>
|
||||||
|
<addaction name="actionCopy"/>
|
||||||
|
<addaction name="actionPaste"/>
|
||||||
|
<addaction name="actionDelete"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionZoom_In"/>
|
||||||
|
<addaction name="actionZoom_Out"/>
|
||||||
|
<addaction name="actionReset_Zoom"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionConnect"/>
|
||||||
|
<addaction name="actionRemove_Connections"/>
|
||||||
|
<addaction name="actionSelect"/>
|
||||||
|
<addaction name="actionPan"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionStart"/>
|
||||||
|
<addaction name="actionStop"/>
|
||||||
|
<addaction name="actionStep"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QToolBar" name="toolBarBottom">
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>toolBar_2</string>
|
||||||
|
</property>
|
||||||
|
<attribute name="toolBarArea">
|
||||||
|
<enum>BottomToolBarArea</enum>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="toolBarBreak">
|
||||||
|
<bool>false</bool>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
|
<action name="actionOpen">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="document-open">
|
||||||
|
<normaloff>.</normaloff>.</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Open</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+O</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSave">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="document-save">
|
||||||
|
<normaloff>.</normaloff>.</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Save</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+S</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSave_As">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="document-save-as">
|
||||||
|
<normaloff>.</normaloff>.</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Save As</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+Shift+S</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionExit">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="document-close">
|
||||||
|
<normaloff>.</normaloff>.</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Exit</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Alt+F4</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionConnect">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="draw-connector">
|
||||||
|
<normaloff>.</normaloff>.</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Connect Parts</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+J</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSelect">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="edit-select">
|
||||||
|
<normaloff>.</normaloff>.</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Select</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+G</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionZoom_In">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="zoom-in">
|
||||||
|
<normaloff>.</normaloff>.</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Zoom In</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+8</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionZoom_Out">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="zoom-out">
|
||||||
|
<normaloff>.</normaloff>.</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Zoom Out</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+9</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionReset_Zoom">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="zoom">
|
||||||
|
<normaloff>.</normaloff>.</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Reset Zoom</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+0</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionPan">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="hand">
|
||||||
|
<normaloff>.</normaloff>.</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Pan</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+H</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionUndo">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="edit-undo">
|
||||||
|
<normaloff>.</normaloff>.</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Undo</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+Z</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionRedo">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="edit-redo">
|
||||||
|
<normaloff>.</normaloff>.</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Redo</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+Y</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionCopy">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="edit-copy">
|
||||||
|
<normaloff>.</normaloff>.</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Copy</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+C</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionCut">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="edit-cut">
|
||||||
|
<normaloff>.</normaloff>.</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Cut</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+X</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionPaste">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="edit-paste">
|
||||||
|
<normaloff>.</normaloff>.</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Paste</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+V</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionRemove_Connections">
|
||||||
|
<property name="checkable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="format-remove-node">
|
||||||
|
<normaloff>.</normaloff>.</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Remove Connections</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+U</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionDelete">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="edit-delete">
|
||||||
|
<normaloff>.</normaloff>.</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Delete</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Del</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionStart">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="media-playback-start">
|
||||||
|
<normaloff>.</normaloff>.</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Start</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionStop">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="media-playback-stop">
|
||||||
|
<normaloff>.</normaloff>.</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Stop</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionStep">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="debug-step-out">
|
||||||
|
<normaloff>.</normaloff>.</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Step</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Step</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionToggle_Undo_View">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="edit-undo-history">
|
||||||
|
<normaloff>.</normaloff>.</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Toggle Undo View</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Toggle Undo View</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionTutorial">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="help">
|
||||||
|
<normaloff>.</normaloff>.</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Tutorial</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionAbout">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="help-about">
|
||||||
|
<normaloff>.</normaloff>.</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>About</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionNew">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="document-new">
|
||||||
|
<normaloff>.</normaloff>.</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>New</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+N</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
</widget>
|
||||||
|
<resources>
|
||||||
|
<include location="Resources.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
188
Part.cpp
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
#include "Part.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QStyleOptionGraphicsItem>
|
||||||
|
#include <QGraphicsSceneDragDropEvent>
|
||||||
|
#include "Connector.h"
|
||||||
|
#include "eConnectorType.h"
|
||||||
|
#include "MainWindow.h"
|
||||||
|
#include "Scene.h"
|
||||||
|
#include "Logic.h"
|
||||||
|
|
||||||
|
// PUBLIC
|
||||||
|
Part::Part(Logic* logic, CircuitItemBaseShape baseShape)
|
||||||
|
:m_logic(logic), m_baseShape(baseShape)
|
||||||
|
{
|
||||||
|
// Set flags
|
||||||
|
setFlag(QGraphicsItem::ItemIsMovable);
|
||||||
|
setFlag(QGraphicsItem::ItemIsSelectable);
|
||||||
|
setFlag(QGraphicsItem::ItemSendsScenePositionChanges);
|
||||||
|
// Set default colors
|
||||||
|
m_penColorNormal=Qt::GlobalColor::color1;
|
||||||
|
m_penColorSelected=Qt::GlobalColor::color0;
|
||||||
|
m_penColorSymbol=Qt::GlobalColor::white;
|
||||||
|
m_brushColorNormal=Qt::GlobalColor::blue;
|
||||||
|
m_brushColorSelected=Qt::GlobalColor::blue;
|
||||||
|
// Set default width factor (actual width = 20 * width factor)
|
||||||
|
setWidth(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
PartType::PartType Part::partType()
|
||||||
|
{
|
||||||
|
return m_partType;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Part::addInputs(int amount)
|
||||||
|
{
|
||||||
|
for(int i = 0; i < amount; i++)
|
||||||
|
{
|
||||||
|
Connector *connector = new Connector(m_logic->parentScene(), this, ConnectorType::Input);
|
||||||
|
m_inputs.append(connector);
|
||||||
|
m_logic->m_inputConnectors.append(connector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Part::addOutputs(int amount)
|
||||||
|
{
|
||||||
|
for(int i = 0; i < amount; i++)
|
||||||
|
{
|
||||||
|
Connector *connector = new Connector(m_logic->parentScene(), this, ConnectorType::Output);
|
||||||
|
m_outputs.append(connector);
|
||||||
|
m_logic->m_outputConnectors.append(connector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Part::setWidth(int factor)
|
||||||
|
{
|
||||||
|
m_widthFactor = factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Part::recalculateLayout()
|
||||||
|
{
|
||||||
|
// Add inputs and outputs and position them correctly
|
||||||
|
int yOffsetInputs;
|
||||||
|
int yOffsetOutputs;
|
||||||
|
if(m_baseShape == RoundedRect)
|
||||||
|
{
|
||||||
|
if(m_outputs.length() > m_inputs.length())
|
||||||
|
{
|
||||||
|
yOffsetInputs = 10 + 10 * (m_outputs.length() - m_inputs.length());
|
||||||
|
yOffsetOutputs = 10;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
yOffsetOutputs = 10 + 10 * (m_inputs.length() - m_outputs.length());
|
||||||
|
yOffsetInputs = 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // if m_baseShape == Circle
|
||||||
|
{
|
||||||
|
yOffsetInputs = 20;
|
||||||
|
yOffsetOutputs = 20;
|
||||||
|
}
|
||||||
|
for(int i = 0; i < m_inputs.length(); i++)
|
||||||
|
{
|
||||||
|
m_inputs[i]->setPos(0, yOffsetInputs + 20 * i);
|
||||||
|
}
|
||||||
|
for(int i = 0; i < m_outputs.length(); i++)
|
||||||
|
{
|
||||||
|
m_outputs[i]->setPos(20 * m_widthFactor, yOffsetOutputs + 20 * i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QRectF Part::boundingRect() const
|
||||||
|
{
|
||||||
|
if(m_baseShape == RoundedRect)
|
||||||
|
{
|
||||||
|
int maxConnections = qMax(m_inputs.length(), m_outputs.length());
|
||||||
|
return QRectF(-1, -1, m_widthFactor * 20 + 2, maxConnections * 20 + 2);
|
||||||
|
}
|
||||||
|
else // if m_baseShape == Circle
|
||||||
|
return QRectF(-1, -1, 42, 42);
|
||||||
|
}
|
||||||
|
|
||||||
|
QPainterPath Part::shape() const
|
||||||
|
{
|
||||||
|
QPainterPath path;
|
||||||
|
if(m_baseShape == RoundedRect)
|
||||||
|
{
|
||||||
|
int maxConnections = qMax(m_inputs.length(), m_outputs.length());
|
||||||
|
path.addRect(-1, -1, m_widthFactor * 20 + 2, maxConnections * 20 + 2);
|
||||||
|
}
|
||||||
|
else // if m_baseShape == Circle
|
||||||
|
path.addRect(-1, -1, 42, 42);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Part::paint(QPainter *painter, const QStyleOptionGraphicsItem *item, QWidget *widget)
|
||||||
|
{
|
||||||
|
Q_UNUSED(widget)
|
||||||
|
|
||||||
|
QPen symbolPen = painter->pen();
|
||||||
|
symbolPen.setColor(m_penColorSymbol);
|
||||||
|
|
||||||
|
QBrush symbolBrush = painter->brush();
|
||||||
|
|
||||||
|
QPen pen = painter->pen();
|
||||||
|
pen.setWidth(2);
|
||||||
|
|
||||||
|
QBrush brush = painter->brush();
|
||||||
|
brush.setStyle(Qt::SolidPattern);
|
||||||
|
|
||||||
|
// Set colors according to state
|
||||||
|
if(item->state & QStyle::State_Selected)
|
||||||
|
{
|
||||||
|
pen.setColor(m_penColorSelected);
|
||||||
|
brush.setColor(m_brushColorSelected);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pen.setColor(m_penColorNormal);
|
||||||
|
brush.setColor(m_brushColorNormal);
|
||||||
|
}
|
||||||
|
painter->setPen(pen);
|
||||||
|
painter->setBrush(brush);
|
||||||
|
|
||||||
|
// Draw base shape
|
||||||
|
int maxConnections = qMax(m_inputs.length(), m_outputs.length());
|
||||||
|
if(m_baseShape == RoundedRect)
|
||||||
|
painter->drawRoundedRect(0, 0, 20 * m_widthFactor, 20 * maxConnections, 5, 5);
|
||||||
|
else // if m_baseShape == Circle
|
||||||
|
painter->drawEllipse(0, 0, 40, 40);
|
||||||
|
// Draw provided symbol
|
||||||
|
QPainterPath painterPath = symbolPainterPath(QRect(-20, -10 * maxConnections, 40, 20 * maxConnections));
|
||||||
|
painter->setPen(symbolPen);
|
||||||
|
painter->setBrush(symbolBrush);
|
||||||
|
painter->translate(20, 10 * maxConnections);
|
||||||
|
painter->drawPath(painterPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant Part::itemChange(GraphicsItemChange change, const QVariant & value)
|
||||||
|
{
|
||||||
|
// Update connectors if selection state has changed; this ensures that their pen color changes with that of the CircuitItem
|
||||||
|
if (change == ItemSelectedHasChanged)
|
||||||
|
{
|
||||||
|
for(auto i : m_inputs)
|
||||||
|
i->update();
|
||||||
|
for(auto o : m_outputs)
|
||||||
|
o->update();
|
||||||
|
}
|
||||||
|
return QGraphicsItem::itemChange(change, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// PRIVATE
|
||||||
|
void Part::updateState()
|
||||||
|
{
|
||||||
|
QVector<bool> inputs;
|
||||||
|
inputs.reserve(m_inputs.length());
|
||||||
|
for(auto connector : m_inputs)
|
||||||
|
inputs.append(connector->m_state);
|
||||||
|
|
||||||
|
QVector<bool> outputs = compute(inputs);
|
||||||
|
for(int i = 0; i < m_outputs.length(); i++)
|
||||||
|
{
|
||||||
|
m_outputs[i]->m_state = outputs[i];
|
||||||
|
}
|
||||||
|
}
|
91
Part.h
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
#ifndef CIRCUITITEM_H
|
||||||
|
#define CIRCUITITEM_H
|
||||||
|
|
||||||
|
#include <QGraphicsItem>
|
||||||
|
#include <QList>
|
||||||
|
|
||||||
|
#include "ePartType.h"
|
||||||
|
|
||||||
|
class Connector;
|
||||||
|
class Logic;
|
||||||
|
|
||||||
|
class Part : public QGraphicsItem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
friend class Connector;
|
||||||
|
friend class Scene;
|
||||||
|
friend class Logic;
|
||||||
|
friend class AddPart;
|
||||||
|
friend class RemoveParts;
|
||||||
|
friend class RemoveWire;
|
||||||
|
friend class CopyParts;
|
||||||
|
|
||||||
|
friend class FileHandler;
|
||||||
|
|
||||||
|
friend class CircuitBuffer;
|
||||||
|
|
||||||
|
friend class MainWindow;
|
||||||
|
|
||||||
|
enum CircuitItemColorType
|
||||||
|
{
|
||||||
|
PenColorNormal,
|
||||||
|
PenColorSelected,
|
||||||
|
PenColorSymbol,
|
||||||
|
BrushColorNormal,
|
||||||
|
BrushColorSelected
|
||||||
|
};
|
||||||
|
|
||||||
|
enum CircuitItemBaseShape
|
||||||
|
{
|
||||||
|
RoundedRect,
|
||||||
|
Circle // Only supports up to 1 input and 1 output
|
||||||
|
};
|
||||||
|
|
||||||
|
Part(Logic* logic, CircuitItemBaseShape baseShape = RoundedRect);
|
||||||
|
|
||||||
|
PartType::PartType partType();
|
||||||
|
|
||||||
|
void addInputs(int amount);
|
||||||
|
void addOutputs(int amount);
|
||||||
|
|
||||||
|
void setWidth(int factor);
|
||||||
|
|
||||||
|
void addText(); //TODO
|
||||||
|
void addTextEdit(); //TODO
|
||||||
|
|
||||||
|
void recalculateLayout();
|
||||||
|
|
||||||
|
virtual QRectF boundingRect() const override;
|
||||||
|
virtual QPainterPath shape() const override;
|
||||||
|
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *item, QWidget *widget) override;
|
||||||
|
// Symbol to be drawn inside the circuitItem
|
||||||
|
virtual QPainterPath symbolPainterPath(QRect limits) = 0;
|
||||||
|
virtual QVariant itemChange(GraphicsItemChange change, const QVariant & value) override;
|
||||||
|
// Take the inputs and calculate the outputs based on the part's logic
|
||||||
|
virtual QVector<bool> compute(QVector<bool> inputs) = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Logic* m_logic;
|
||||||
|
|
||||||
|
QVector<Connector*> m_inputs;
|
||||||
|
QVector<Connector*> m_outputs;
|
||||||
|
|
||||||
|
QColor m_penColorNormal;
|
||||||
|
QColor m_penColorSelected;
|
||||||
|
QColor m_penColorSymbol;
|
||||||
|
QColor m_brushColorNormal;
|
||||||
|
QColor m_brushColorSelected;
|
||||||
|
|
||||||
|
CircuitItemBaseShape m_baseShape;
|
||||||
|
|
||||||
|
QPointF m_oldPos;
|
||||||
|
|
||||||
|
PartType::PartType m_partType;
|
||||||
|
|
||||||
|
int m_widthFactor;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Updates all of the outputs using the inputs
|
||||||
|
void updateState();
|
||||||
|
};
|
||||||
|
#endif // CIRCUITITEM_H
|
44
Parts/AndGate.cpp
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#include "AndGate.h"
|
||||||
|
|
||||||
|
#include "../Connector.h"
|
||||||
|
|
||||||
|
AndGate::AndGate(Logic* logic)
|
||||||
|
:Part(logic)
|
||||||
|
{
|
||||||
|
addInputs(2);
|
||||||
|
addOutputs(1);
|
||||||
|
recalculateLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<bool> AndGate::compute(QVector<bool> inputs)
|
||||||
|
{
|
||||||
|
QVector<bool> ret(1);
|
||||||
|
ret[0] = inputs[0] && inputs[1];
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPainterPath AndGate::symbolPainterPath(QRect limits)
|
||||||
|
{
|
||||||
|
Q_UNUSED(limits)
|
||||||
|
QPainterPath painterPath;
|
||||||
|
|
||||||
|
// Left vertical line
|
||||||
|
painterPath.moveTo(-8, 8);
|
||||||
|
painterPath.lineTo(-8, -8);
|
||||||
|
// Upper horizontal line
|
||||||
|
painterPath.lineTo(-2, -8);
|
||||||
|
// Right arc
|
||||||
|
painterPath.cubicTo(11, -8, 11, 8, -2, 8);
|
||||||
|
// Lower horizontal line
|
||||||
|
painterPath.lineTo(-8, 8);
|
||||||
|
// Upper input line
|
||||||
|
painterPath.moveTo(-14, -4);
|
||||||
|
painterPath.lineTo(-8, -4);
|
||||||
|
// Lower input line
|
||||||
|
painterPath.moveTo(-14, 4);
|
||||||
|
painterPath.lineTo(-8, 4);
|
||||||
|
// Output line
|
||||||
|
painterPath.moveTo(8, 0);
|
||||||
|
painterPath.lineTo(14, 0);
|
||||||
|
return painterPath;
|
||||||
|
}
|
15
Parts/AndGate.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef ANDGATE_H
|
||||||
|
#define ANDGATE_H
|
||||||
|
|
||||||
|
#include "../Part.h"
|
||||||
|
|
||||||
|
class AndGate : public Part
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AndGate(Logic* logic);
|
||||||
|
|
||||||
|
QVector<bool> compute(QVector<bool> inputs) override;
|
||||||
|
QPainterPath symbolPainterPath(QRect limits) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ANDGATE_H
|
38
Parts/BufferGate.cpp
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#include "BufferGate.h"
|
||||||
|
|
||||||
|
#include "../Connector.h"
|
||||||
|
|
||||||
|
BufferGate::BufferGate(Logic* logic)
|
||||||
|
:Part(logic)
|
||||||
|
{
|
||||||
|
addInputs(1);
|
||||||
|
addOutputs(1);
|
||||||
|
recalculateLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<bool> BufferGate::compute(QVector<bool> inputs)
|
||||||
|
{
|
||||||
|
QVector<bool> ret(1);
|
||||||
|
ret[0] = inputs[0];
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPainterPath BufferGate::symbolPainterPath(QRect limits)
|
||||||
|
{
|
||||||
|
Q_UNUSED(limits)
|
||||||
|
QPainterPath painterPath;
|
||||||
|
QPolygon triangle;
|
||||||
|
triangle.append(QPoint(-8, 8));
|
||||||
|
triangle.append(QPoint(-8, -8));
|
||||||
|
triangle.append(QPoint(8, 0));
|
||||||
|
triangle.append(QPoint(-8, 8));
|
||||||
|
painterPath.addPolygon(triangle);
|
||||||
|
// Input line
|
||||||
|
painterPath.moveTo(-14, 0);
|
||||||
|
painterPath.lineTo(-8, 0);
|
||||||
|
// Output line
|
||||||
|
painterPath.moveTo(8, 0);
|
||||||
|
painterPath.lineTo(14, 0);
|
||||||
|
return painterPath;
|
||||||
|
}
|
15
Parts/BufferGate.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef BUFFERGATE_H
|
||||||
|
#define BUFFERGATE_H
|
||||||
|
|
||||||
|
#include "../Part.h"
|
||||||
|
|
||||||
|
class BufferGate : public Part
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BufferGate(Logic* logic);
|
||||||
|
|
||||||
|
QVector<bool> compute(QVector<bool> inputs) override;
|
||||||
|
QPainterPath symbolPainterPath(QRect limits) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BUFFERGATE_H
|
26
Parts/HighConstant.cpp
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#include "HighConstant.h"
|
||||||
|
|
||||||
|
#include "../Connector.h"
|
||||||
|
|
||||||
|
HighConstant::HighConstant(Logic* logic)
|
||||||
|
:Part(logic, Circle)
|
||||||
|
{
|
||||||
|
addInputs(0);
|
||||||
|
addOutputs(1);
|
||||||
|
recalculateLayout();
|
||||||
|
m_brushColorNormal = Qt::GlobalColor::green;
|
||||||
|
m_brushColorSelected = Qt::GlobalColor::green;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<bool> HighConstant::compute(QVector<bool> inputs)
|
||||||
|
{
|
||||||
|
QVector<bool> ret(1);
|
||||||
|
ret[0] = true;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPainterPath HighConstant::symbolPainterPath(QRect limits)
|
||||||
|
{
|
||||||
|
Q_UNUSED(limits)
|
||||||
|
return QPainterPath();
|
||||||
|
}
|
15
Parts/HighConstant.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef HIGHCONSTANT_H
|
||||||
|
#define HIGHCONSTANT_H
|
||||||
|
|
||||||
|
#include "../Part.h"
|
||||||
|
|
||||||
|
class HighConstant : public Part
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HighConstant(Logic* logic);
|
||||||
|
|
||||||
|
QVector<bool> compute(QVector<bool> inputs) override;
|
||||||
|
QPainterPath symbolPainterPath(QRect limits) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // HIGHCONSTANT_H
|
56
Parts/IntegratedCircuit.cpp
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
#include "IntegratedCircuit.h"
|
||||||
|
|
||||||
|
#include "../Scene.h"
|
||||||
|
#include "../Logic.h"
|
||||||
|
#include "ToggleButton.h"
|
||||||
|
#include "LightBulb.h"
|
||||||
|
|
||||||
|
static bool compareToggleButtons(const ToggleButton* a, const ToggleButton* b) { return a->y() < b->y(); }
|
||||||
|
static bool compareLightBulbs(const LightBulb* a, const LightBulb* b) { return a->y() < b->y(); }
|
||||||
|
|
||||||
|
IntegratedCircuit::IntegratedCircuit(Logic* logic, QString filename)
|
||||||
|
:Part(logic), m_filename(filename), m_icLogic(new Logic)
|
||||||
|
{
|
||||||
|
setWidth(4);
|
||||||
|
|
||||||
|
m_icLogic->loadFromFile(filename);
|
||||||
|
|
||||||
|
for(auto part : m_icLogic->m_parts)
|
||||||
|
{
|
||||||
|
if(part->partType() == PartType::IOToggleButton)
|
||||||
|
m_icLogicInputs.append((ToggleButton*)part);
|
||||||
|
else if(part->partType() == PartType::IOLightBulb)
|
||||||
|
m_icLogicOutputs.append((LightBulb*)part);
|
||||||
|
}
|
||||||
|
|
||||||
|
addInputs(m_icLogicInputs.length());
|
||||||
|
addOutputs(m_icLogicOutputs.length());
|
||||||
|
|
||||||
|
// Sort according to y position
|
||||||
|
std::sort(m_icLogicInputs.begin(), m_icLogicInputs.end(), compareToggleButtons);
|
||||||
|
std::sort(m_icLogicOutputs.begin(), m_icLogicOutputs.end(), compareLightBulbs);
|
||||||
|
|
||||||
|
recalculateLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString IntegratedCircuit::filename()
|
||||||
|
{
|
||||||
|
return m_filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<bool> IntegratedCircuit::compute(QVector<bool> inputs)
|
||||||
|
{
|
||||||
|
for(int i = 0; i < inputs.length(); i++)
|
||||||
|
m_icLogicInputs[i]->m_toggleState = inputs[i];
|
||||||
|
m_icLogic->doLogicStep();
|
||||||
|
QVector<bool> ret(m_icLogicOutputs.length());
|
||||||
|
for(int i = 0; i < m_icLogicOutputs.length(); i++)
|
||||||
|
ret[i] = m_icLogicOutputs[i]->m_state;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPainterPath IntegratedCircuit::symbolPainterPath(QRect limits)
|
||||||
|
{
|
||||||
|
Q_UNUSED(limits)
|
||||||
|
return QPainterPath();
|
||||||
|
}
|
31
Parts/IntegratedCircuit.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#ifndef INTEGRATEDCIRCUIT_H
|
||||||
|
#define INTEGRATEDCIRCUIT_H
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
#include "../Part.h"
|
||||||
|
|
||||||
|
class Logic;
|
||||||
|
class ToggleButton;
|
||||||
|
class LightBulb;
|
||||||
|
|
||||||
|
class IntegratedCircuit : public Part
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
IntegratedCircuit(Logic* logic, QString filename = "");
|
||||||
|
|
||||||
|
QString filename();
|
||||||
|
|
||||||
|
QVector<bool> compute(QVector<bool> inputs) override;
|
||||||
|
QPainterPath symbolPainterPath(QRect limits) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString m_filename;
|
||||||
|
|
||||||
|
Logic* m_icLogic;
|
||||||
|
|
||||||
|
QVector<ToggleButton*> m_icLogicInputs;
|
||||||
|
QVector<LightBulb*> m_icLogicOutputs;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // INTEGRATEDCIRCUIT_H
|
38
Parts/LightBulb.cpp
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#include "LightBulb.h"
|
||||||
|
|
||||||
|
#include "../Connector.h"
|
||||||
|
|
||||||
|
LightBulb::LightBulb(Logic* logic)
|
||||||
|
:Part(logic, Circle)
|
||||||
|
{
|
||||||
|
addInputs(1);
|
||||||
|
addOutputs(0);
|
||||||
|
recalculateLayout();
|
||||||
|
m_brushColorNormal = Qt::GlobalColor::black;
|
||||||
|
m_brushColorSelected = Qt::GlobalColor::black;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<bool> LightBulb::compute(QVector<bool> inputs)
|
||||||
|
{
|
||||||
|
m_state = inputs[0];
|
||||||
|
|
||||||
|
// Set color according to input state (on or off)
|
||||||
|
if(m_state)
|
||||||
|
{
|
||||||
|
m_brushColorNormal = Qt::GlobalColor::green;
|
||||||
|
m_brushColorSelected = Qt::GlobalColor::green;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_brushColorNormal = Qt::GlobalColor::black;
|
||||||
|
m_brushColorSelected = Qt::GlobalColor::black;
|
||||||
|
}
|
||||||
|
|
||||||
|
return QVector<bool>();
|
||||||
|
}
|
||||||
|
|
||||||
|
QPainterPath LightBulb::symbolPainterPath(QRect limits)
|
||||||
|
{
|
||||||
|
Q_UNUSED(limits)
|
||||||
|
return QPainterPath();
|
||||||
|
}
|
21
Parts/LightBulb.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#ifndef LAMP_H
|
||||||
|
#define LAMP_H
|
||||||
|
|
||||||
|
#include "../Part.h"
|
||||||
|
|
||||||
|
class LightBulb : public Part
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
friend class IntegratedCircuit;
|
||||||
|
|
||||||
|
LightBulb(Logic* logic);
|
||||||
|
|
||||||
|
QVector<bool> compute(QVector<bool> inputs) override;
|
||||||
|
QPainterPath symbolPainterPath(QRect limits) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_state = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // LAMP_H
|
26
Parts/LowConstant.cpp
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#include "LowConstant.h"
|
||||||
|
|
||||||
|
#include "../Connector.h"
|
||||||
|
|
||||||
|
LowConstant::LowConstant(Logic* logic)
|
||||||
|
:Part(logic, Circle)
|
||||||
|
{
|
||||||
|
addInputs(0);
|
||||||
|
addOutputs(1);
|
||||||
|
recalculateLayout();
|
||||||
|
m_brushColorNormal = Qt::GlobalColor::black;
|
||||||
|
m_brushColorSelected = Qt::GlobalColor::black;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<bool> LowConstant::compute(QVector<bool> inputs)
|
||||||
|
{
|
||||||
|
QVector<bool> ret(1);
|
||||||
|
ret[0] = false;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPainterPath LowConstant::symbolPainterPath(QRect limits)
|
||||||
|
{
|
||||||
|
Q_UNUSED(limits)
|
||||||
|
return QPainterPath();
|
||||||
|
}
|
15
Parts/LowConstant.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef LOWCONSTANT_H
|
||||||
|
#define LOWCONSTANT_H
|
||||||
|
|
||||||
|
#include "../Part.h"
|
||||||
|
|
||||||
|
class LowConstant : public Part
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LowConstant(Logic* logic);
|
||||||
|
|
||||||
|
QVector<bool> compute(QVector<bool> inputs) override;
|
||||||
|
QPainterPath symbolPainterPath(QRect limits) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // LOWCONSTANT_H
|
46
Parts/NandGate.cpp
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#include "NandGate.h"
|
||||||
|
|
||||||
|
#include "../Connector.h"
|
||||||
|
|
||||||
|
NandGate::NandGate(Logic* logic)
|
||||||
|
:Part(logic)
|
||||||
|
{
|
||||||
|
addInputs(2);
|
||||||
|
addOutputs(1);
|
||||||
|
recalculateLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<bool> NandGate::compute(QVector<bool> inputs)
|
||||||
|
{
|
||||||
|
QVector<bool> ret(1);
|
||||||
|
ret[0] = !(inputs[0] && inputs[1]);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPainterPath NandGate::symbolPainterPath(QRect limits)
|
||||||
|
{
|
||||||
|
Q_UNUSED(limits)
|
||||||
|
QPainterPath painterPath;
|
||||||
|
|
||||||
|
// Left vertical line
|
||||||
|
painterPath.moveTo(-8, 8);
|
||||||
|
painterPath.lineTo(-8, -8);
|
||||||
|
// Upper horizontal line
|
||||||
|
painterPath.lineTo(-2, -8);
|
||||||
|
// Right arc
|
||||||
|
painterPath.cubicTo(11, -8, 11, 8, -2, 8);
|
||||||
|
// Lower horizontal line
|
||||||
|
painterPath.lineTo(-8, 8);
|
||||||
|
// Inverting dot
|
||||||
|
painterPath.addEllipse(8.f, -1.5f, 3.f, 3.f);
|
||||||
|
// Upper input line
|
||||||
|
painterPath.moveTo(-14, -4);
|
||||||
|
painterPath.lineTo(-8, -4);
|
||||||
|
// Lower input line
|
||||||
|
painterPath.moveTo(-14, 4);
|
||||||
|
painterPath.lineTo(-8, 4);
|
||||||
|
// Output line
|
||||||
|
painterPath.moveTo(11.5f, 0.f);
|
||||||
|
painterPath.lineTo(14, 0);
|
||||||
|
return painterPath;
|
||||||
|
}
|
15
Parts/NandGate.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef NANDGATE_H
|
||||||
|
#define NANDGATE_H
|
||||||
|
|
||||||
|
#include "../Part.h"
|
||||||
|
|
||||||
|
class NandGate : public Part
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NandGate(Logic* logic);
|
||||||
|
|
||||||
|
QVector<bool> compute(QVector<bool> inputs) override;
|
||||||
|
QPainterPath symbolPainterPath(QRect limits) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // NANDGATE_H
|
49
Parts/NorGate.cpp
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#include "NorGate.h"
|
||||||
|
|
||||||
|
#include "../Connector.h"
|
||||||
|
|
||||||
|
NorGate::NorGate(Logic* logic)
|
||||||
|
:Part(logic)
|
||||||
|
{
|
||||||
|
addInputs(2);
|
||||||
|
addOutputs(1);
|
||||||
|
recalculateLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<bool> NorGate::compute(QVector<bool> inputs)
|
||||||
|
{
|
||||||
|
QVector<bool> ret(1);
|
||||||
|
ret[0] = !(inputs[0] || inputs[1]);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPainterPath NorGate::symbolPainterPath(QRect limits)
|
||||||
|
{
|
||||||
|
Q_UNUSED(limits)
|
||||||
|
QPainterPath painterPath;
|
||||||
|
// Left arc
|
||||||
|
painterPath.moveTo(-10, -8);
|
||||||
|
painterPath.quadTo(-2, 0, -10, 8);
|
||||||
|
// Lower line
|
||||||
|
painterPath.lineTo(-2, 8);
|
||||||
|
// Lower arc
|
||||||
|
painterPath.quadTo(5, 6, 8, 0);
|
||||||
|
//
|
||||||
|
painterPath.moveTo(-10, -8);
|
||||||
|
// Upper line
|
||||||
|
painterPath.lineTo(-2, -8);
|
||||||
|
// Upper arc
|
||||||
|
painterPath.quadTo(5, -6, 8, 0);
|
||||||
|
// Inverting dot
|
||||||
|
painterPath.addEllipse(8.f, -1.5f, 3.f, 3.f);
|
||||||
|
// Upper input line
|
||||||
|
painterPath.moveTo(-14, -4);
|
||||||
|
painterPath.lineTo(-7.5f, -4.f);
|
||||||
|
// Lower input line
|
||||||
|
painterPath.moveTo(-14, 4);
|
||||||
|
painterPath.lineTo(-7.5f, 4.f);
|
||||||
|
// Output line
|
||||||
|
painterPath.moveTo(11.5f, 0.f);
|
||||||
|
painterPath.lineTo(14, 0);
|
||||||
|
return painterPath;
|
||||||
|
}
|
15
Parts/NorGate.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef NORGATE_H
|
||||||
|
#define NORGATE_H
|
||||||
|
|
||||||
|
#include "../Part.h"
|
||||||
|
|
||||||
|
class NorGate : public Part
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NorGate(Logic* logic);
|
||||||
|
|
||||||
|
QVector<bool> compute(QVector<bool> inputs) override;
|
||||||
|
QPainterPath symbolPainterPath(QRect limits) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // NORGATE_H
|
39
Parts/NotGate.cpp
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#include "NotGate.h"
|
||||||
|
|
||||||
|
#include "../Connector.h"
|
||||||
|
|
||||||
|
NotGate::NotGate(Logic* logic)
|
||||||
|
:Part(logic)
|
||||||
|
{
|
||||||
|
addInputs(1);
|
||||||
|
addOutputs(1);
|
||||||
|
recalculateLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<bool> NotGate::compute(QVector<bool> inputs)
|
||||||
|
{
|
||||||
|
QVector<bool> ret(1);
|
||||||
|
ret[0] = !inputs[0];
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPainterPath NotGate::symbolPainterPath(QRect limits)
|
||||||
|
{
|
||||||
|
Q_UNUSED(limits)
|
||||||
|
QPainterPath painterPath;
|
||||||
|
QPolygon triangle;
|
||||||
|
triangle.append(QPoint(-8, 8));
|
||||||
|
triangle.append(QPoint(-8, -8));
|
||||||
|
triangle.append(QPoint(8, 0));
|
||||||
|
triangle.append(QPoint(-8, 8));
|
||||||
|
painterPath.addPolygon(triangle);
|
||||||
|
// Inverting dot
|
||||||
|
painterPath.addEllipse(8.f, -1.5f, 3.f, 3.f);
|
||||||
|
// Input line
|
||||||
|
painterPath.moveTo(-14, 0);
|
||||||
|
painterPath.lineTo(-8, 0);
|
||||||
|
// Output line
|
||||||
|
painterPath.moveTo(11.5f, 0.f);
|
||||||
|
painterPath.lineTo(14, 0);
|
||||||
|
return painterPath;
|
||||||
|
}
|
15
Parts/NotGate.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef NOTGATE_H
|
||||||
|
#define NOTGATE_H
|
||||||
|
|
||||||
|
#include "../Part.h"
|
||||||
|
|
||||||
|
class NotGate : public Part
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NotGate(Logic* logic);
|
||||||
|
|
||||||
|
QVector<bool> compute(QVector<bool> inputs) override;
|
||||||
|
QPainterPath symbolPainterPath(QRect limits) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // NOTGATE_H
|
47
Parts/OrGate.cpp
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#include "OrGate.h"
|
||||||
|
|
||||||
|
#include "../Connector.h"
|
||||||
|
|
||||||
|
OrGate::OrGate(Logic* logic)
|
||||||
|
:Part(logic)
|
||||||
|
{
|
||||||
|
addInputs(2);
|
||||||
|
addOutputs(1);
|
||||||
|
recalculateLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<bool> OrGate::compute(QVector<bool> inputs)
|
||||||
|
{
|
||||||
|
QVector<bool> ret(1);
|
||||||
|
ret[0] = inputs[0] || inputs[1];
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPainterPath OrGate::symbolPainterPath(QRect limits)
|
||||||
|
{
|
||||||
|
Q_UNUSED(limits)
|
||||||
|
QPainterPath painterPath;
|
||||||
|
// Left arc
|
||||||
|
painterPath.moveTo(-10, -8);
|
||||||
|
painterPath.quadTo(-2, 0, -10, 8);
|
||||||
|
// Lower line
|
||||||
|
painterPath.lineTo(-2, 8);
|
||||||
|
// Lower arc
|
||||||
|
painterPath.quadTo(5, 6, 8, 0);
|
||||||
|
//
|
||||||
|
painterPath.moveTo(-10, -8);
|
||||||
|
// Upper line
|
||||||
|
painterPath.lineTo(-2, -8);
|
||||||
|
// Upper arc
|
||||||
|
painterPath.quadTo(5, -6, 8, 0);
|
||||||
|
// Upper input line
|
||||||
|
painterPath.moveTo(-14, -4);
|
||||||
|
painterPath.lineTo(-7.5f, -4.f);
|
||||||
|
// Lower input line
|
||||||
|
painterPath.moveTo(-14, 4);
|
||||||
|
painterPath.lineTo(-7.5f, 4.f);
|
||||||
|
// Output line
|
||||||
|
painterPath.moveTo(8, 0);
|
||||||
|
painterPath.lineTo(14, 0);
|
||||||
|
return painterPath;
|
||||||
|
}
|
15
Parts/OrGate.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef ORGATE_H
|
||||||
|
#define ORGATE_H
|
||||||
|
|
||||||
|
#include "../Part.h"
|
||||||
|
|
||||||
|
class OrGate : public Part
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OrGate(Logic* logic);
|
||||||
|
|
||||||
|
QVector<bool> compute(QVector<bool> inputs) override;
|
||||||
|
QPainterPath symbolPainterPath(QRect limits) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ORGATE_H
|
43
Parts/ToggleButton.cpp
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#include "ToggleButton.h"
|
||||||
|
|
||||||
|
#include <QGraphicsSceneMouseEvent>
|
||||||
|
|
||||||
|
ToggleButton::ToggleButton(Logic* logic)
|
||||||
|
:Part(logic, Circle)
|
||||||
|
{
|
||||||
|
addInputs(0);
|
||||||
|
addOutputs(1);
|
||||||
|
recalculateLayout();
|
||||||
|
m_brushColorNormal = Qt::GlobalColor::red;
|
||||||
|
m_brushColorSelected = Qt::GlobalColor::red;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<bool> ToggleButton::compute(QVector<bool> inputs)
|
||||||
|
{
|
||||||
|
QVector<bool> ret(1);
|
||||||
|
ret[0] = m_toggleState;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPainterPath ToggleButton::symbolPainterPath(QRect limits)
|
||||||
|
{
|
||||||
|
Q_UNUSED(limits)
|
||||||
|
return QPainterPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToggleButton::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
|
||||||
|
{
|
||||||
|
m_toggleState = !m_toggleState;
|
||||||
|
if(m_toggleState)
|
||||||
|
{
|
||||||
|
m_brushColorNormal = Qt::GlobalColor::darkRed;
|
||||||
|
m_brushColorSelected = Qt::GlobalColor::darkRed;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_brushColorNormal = Qt::GlobalColor::red;
|
||||||
|
m_brushColorSelected = Qt::GlobalColor::red;
|
||||||
|
}
|
||||||
|
update();
|
||||||
|
Part::mouseDoubleClickEvent(event);
|
||||||
|
}
|
24
Parts/ToggleButton.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#ifndef TOGGLEBUTTON_H
|
||||||
|
#define TOGGLEBUTTON_H
|
||||||
|
|
||||||
|
#include "../Part.h"
|
||||||
|
|
||||||
|
class ToggleButton : public Part
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
friend class IntegratedCircuit;
|
||||||
|
|
||||||
|
ToggleButton(Logic* logic);
|
||||||
|
|
||||||
|
QVector<bool> compute(QVector<bool> inputs) override;
|
||||||
|
QPainterPath symbolPainterPath(QRect limits) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) override;
|
||||||
|
|
||||||
|
QPointF m_dragBeginPos;
|
||||||
|
|
||||||
|
bool m_toggleState = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // TOGGLEBUTTON_H
|
52
Parts/XnorGate.cpp
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
#include "XnorGate.h"
|
||||||
|
|
||||||
|
#include "../Connector.h"
|
||||||
|
|
||||||
|
XnorGate::XnorGate(Logic* logic)
|
||||||
|
:Part(logic)
|
||||||
|
{
|
||||||
|
addInputs(2);
|
||||||
|
addOutputs(1);
|
||||||
|
recalculateLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<bool> XnorGate::compute(QVector<bool> inputs)
|
||||||
|
{
|
||||||
|
QVector<bool> ret(1);
|
||||||
|
ret[0] = !((inputs[0] || inputs[1]) && (!(inputs[0] && inputs[1])));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPainterPath XnorGate::symbolPainterPath(QRect limits)
|
||||||
|
{
|
||||||
|
Q_UNUSED(limits)
|
||||||
|
QPainterPath painterPath;
|
||||||
|
// 0th Left arc
|
||||||
|
painterPath.moveTo(-12, -8);
|
||||||
|
painterPath.quadTo(-4, 0, -12, 8);
|
||||||
|
// 1st Left arc
|
||||||
|
painterPath.moveTo(-10, -8);
|
||||||
|
painterPath.quadTo(-2, 0, -10, 8);
|
||||||
|
// Lower line
|
||||||
|
painterPath.lineTo(-2, 8);
|
||||||
|
// Lower arc
|
||||||
|
painterPath.quadTo(5, 6, 8, 0);
|
||||||
|
//
|
||||||
|
painterPath.moveTo(-10, -8);
|
||||||
|
// Upper line
|
||||||
|
painterPath.lineTo(-2, -8);
|
||||||
|
// Upper arc
|
||||||
|
painterPath.quadTo(5, -6, 8, 0);
|
||||||
|
// Inverting dot
|
||||||
|
painterPath.addEllipse(8.f, -1.5f, 3.f, 3.f);
|
||||||
|
// Upper input line
|
||||||
|
painterPath.moveTo(-14, -4);
|
||||||
|
painterPath.lineTo(-7.5f, -4.f);
|
||||||
|
// Lower input line
|
||||||
|
painterPath.moveTo(-14, 4);
|
||||||
|
painterPath.lineTo(-7.5f, 4.f);
|
||||||
|
// Output line
|
||||||
|
painterPath.moveTo(11.5f, 0.f);
|
||||||
|
painterPath.lineTo(14, 0);
|
||||||
|
return painterPath;
|
||||||
|
}
|
15
Parts/XnorGate.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef XNORGATE_H
|
||||||
|
#define XNORGATE_H
|
||||||
|
|
||||||
|
#include "../Part.h"
|
||||||
|
|
||||||
|
class XnorGate : public Part
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
XnorGate(Logic* logic);
|
||||||
|
|
||||||
|
QVector<bool> compute(QVector<bool> inputs) override;
|
||||||
|
QPainterPath symbolPainterPath(QRect limits) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // XNORGATE_H
|
50
Parts/XorGate.cpp
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#include "XorGate.h"
|
||||||
|
|
||||||
|
#include "../Connector.h"
|
||||||
|
|
||||||
|
XorGate::XorGate(Logic* logic)
|
||||||
|
:Part(logic)
|
||||||
|
{
|
||||||
|
addInputs(2);
|
||||||
|
addOutputs(1);
|
||||||
|
recalculateLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<bool> XorGate::compute(QVector<bool> inputs)
|
||||||
|
{
|
||||||
|
QVector<bool> ret(1);
|
||||||
|
ret[0] = (inputs[0] || inputs[1]) && (!(inputs[0] && inputs[1]));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPainterPath XorGate::symbolPainterPath(QRect limits)
|
||||||
|
{
|
||||||
|
Q_UNUSED(limits)
|
||||||
|
QPainterPath painterPath;
|
||||||
|
// 0th Left arc
|
||||||
|
painterPath.moveTo(-12, -8);
|
||||||
|
painterPath.quadTo(-4, 0, -12, 8);
|
||||||
|
// 1st Left arc
|
||||||
|
painterPath.moveTo(-10, -8);
|
||||||
|
painterPath.quadTo(-2, 0, -10, 8);
|
||||||
|
// Lower line
|
||||||
|
painterPath.lineTo(-2, 8);
|
||||||
|
// Lower arc
|
||||||
|
painterPath.quadTo(5, 6, 8, 0);
|
||||||
|
//
|
||||||
|
painterPath.moveTo(-10, -8);
|
||||||
|
// Upper line
|
||||||
|
painterPath.lineTo(-2, -8);
|
||||||
|
// Upper arc
|
||||||
|
painterPath.quadTo(5, -6, 8, 0);
|
||||||
|
// Upper input line
|
||||||
|
painterPath.moveTo(-14, -4);
|
||||||
|
painterPath.lineTo(-7.5f, -4.f);
|
||||||
|
// Lower input line
|
||||||
|
painterPath.moveTo(-14, 4);
|
||||||
|
painterPath.lineTo(-7.5f, 4.f);
|
||||||
|
// Output line
|
||||||
|
painterPath.moveTo(8, 0);
|
||||||
|
painterPath.lineTo(14, 0);
|
||||||
|
return painterPath;
|
||||||
|
}
|
15
Parts/XorGate.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef XORGATE_H
|
||||||
|
#define XORGATE_H
|
||||||
|
|
||||||
|
#include "../Part.h"
|
||||||
|
|
||||||
|
class XorGate : public Part
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
XorGate(Logic* logic);
|
||||||
|
|
||||||
|
QVector<bool> compute(QVector<bool> inputs) override;
|
||||||
|
QPainterPath symbolPainterPath(QRect limits) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // XORGATE_H
|
24
README.md
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# Circuit Logic Simulator #
|
||||||
|
### Build Instructions ###
|
||||||
|
1. **Install dependencies:**
|
||||||
|
- Qt base: `qt5-base`
|
||||||
|
- QMake: `qt5-tools`
|
||||||
|
- Compiler: `g++` (>= 7) or `clang` (>=5)
|
||||||
|
- Note that your distro's package names might vary. All provided package names are those used by Archlinux, the distro this is being tested on.
|
||||||
|
2. **Clone the repository and cd into it:**
|
||||||
|
$`git clone https://github.com/xypwn/circuit-logic-simulator.git`
|
||||||
|
$`cd circuit-logic-simulator`
|
||||||
|
3. **Create a build directory and cd into it:**
|
||||||
|
$`mkdir build`
|
||||||
|
$`cd build`
|
||||||
|
4. **Configure build using QMake:**
|
||||||
|
$`qmake ..`
|
||||||
|
5. **Start build (replace 4 with the number of threads you have to speed it up)**
|
||||||
|
$`make -j 4`
|
||||||
|
6. **Run the executable:**
|
||||||
|
There should now be an executable file called `CircuitSimulator` in your
|
||||||
|
build folder. You can put it anywhere or run it with:
|
||||||
|
$`./CircuitSimulator`
|
||||||
|
### Notes ###
|
||||||
|
- The software is currently under heavy development and therefore still crawling with bugs
|
||||||
|
- The `About` and `Tutorial` menu item haven't yet been implemented
|
12
Resources.qrc
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<RCC>
|
||||||
|
<qresource prefix="/Icons">
|
||||||
|
<file>Resources/AND.png</file>
|
||||||
|
<file>Resources/BUFFER.png</file>
|
||||||
|
<file>Resources/NAND.png</file>
|
||||||
|
<file>Resources/NOR.png</file>
|
||||||
|
<file>Resources/NOT.png</file>
|
||||||
|
<file>Resources/OR.png</file>
|
||||||
|
<file>Resources/XNOR.png</file>
|
||||||
|
<file>Resources/XOR.png</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
BIN
Resources/AND.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
Resources/BUFFER.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
Resources/NAND.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
Resources/NOR.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
Resources/NOT.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
Resources/OR.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
Resources/XNOR.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
Resources/XOR.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
257
Scene.cpp
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
#include "Scene.h"
|
||||||
|
|
||||||
|
#include <MainWindow.h>
|
||||||
|
#include <QGraphicsView>
|
||||||
|
#include <QGraphicsSceneMouseEvent>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include "Connector.h"
|
||||||
|
#include "Wire.h"
|
||||||
|
#include "Part.h"
|
||||||
|
|
||||||
|
#include "UndoCommands/AddPart.h"
|
||||||
|
#include "UndoCommands/AddWire.h"
|
||||||
|
#include "UndoCommands/MoveParts.h"
|
||||||
|
#include "UndoCommands/RemoveParts.h"
|
||||||
|
#include "UndoCommands/RemoveWire.h"
|
||||||
|
//#include "UndoCommands/CopyParts.h"
|
||||||
|
|
||||||
|
#include "FileHandler.h"
|
||||||
|
|
||||||
|
#include "Logic.h"
|
||||||
|
|
||||||
|
|
||||||
|
Scene::Scene(QGraphicsView *parentGfxView, MainWindow *parentMainWindow)
|
||||||
|
:m_parentMainWindow(parentMainWindow), m_parentGfxView(parentGfxView), m_logic(new Logic(this)), m_undoStack(new QUndoStack)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Scene::~Scene()
|
||||||
|
{
|
||||||
|
delete m_logic;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scene::updateGraphics()
|
||||||
|
{
|
||||||
|
// Update all wires graphically
|
||||||
|
for(auto wire : m_logic->m_wires)
|
||||||
|
{
|
||||||
|
wire->updateLine();
|
||||||
|
wire->update();
|
||||||
|
}
|
||||||
|
// Update all parts graphically
|
||||||
|
for(auto part : m_logic->m_parts)
|
||||||
|
{
|
||||||
|
part->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scene::undo()
|
||||||
|
{
|
||||||
|
m_undoStack->undo();
|
||||||
|
m_parentMainWindow->changeMade();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scene::redo()
|
||||||
|
{
|
||||||
|
m_undoStack->redo();
|
||||||
|
m_parentMainWindow->changeMade();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scene::initCopy(const QList<Part*> &parts, const QList<Wire*> &wires)
|
||||||
|
{
|
||||||
|
m_copyBuffer.clear();
|
||||||
|
m_copyBuffer.addFromScene(parts, wires);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scene::doCopy(bool relToMousePos)
|
||||||
|
{
|
||||||
|
// Get scene cursor pos
|
||||||
|
QPoint gfxViewCursorPos = m_parentGfxView->mapFromGlobal(QCursor::pos());
|
||||||
|
QPointF sceneCursorPos = m_parentGfxView->mapToScene(gfxViewCursorPos);
|
||||||
|
|
||||||
|
// Get graphics view center scene coordinates
|
||||||
|
QPointF gfxViewSceneCenter = m_parentGfxView->mapToScene(m_parentGfxView->viewport()->rect().center());
|
||||||
|
|
||||||
|
CopyParts* copyPartsCommand;
|
||||||
|
if(relToMousePos)
|
||||||
|
// Paste in the parts with an offset of: (mouse pos) - (average part pos)
|
||||||
|
// Because the offset is relative to the part's previous position
|
||||||
|
copyPartsCommand = new CopyParts(this, m_copyBuffer, sceneCursorPos - m_copyBuffer.getAvgPartPos());
|
||||||
|
else
|
||||||
|
copyPartsCommand = new CopyParts(this, m_copyBuffer, gfxViewSceneCenter - m_copyBuffer.getAvgPartPos());
|
||||||
|
m_undoStack->push(copyPartsCommand);
|
||||||
|
|
||||||
|
// Unselect all parts
|
||||||
|
for(auto selectedPart : selectedItems())
|
||||||
|
selectedPart->setSelected(false);
|
||||||
|
|
||||||
|
// Select all recently copied parts
|
||||||
|
for(auto part : copyPartsCommand->m_copiedParts)
|
||||||
|
part->setSelected(true);
|
||||||
|
|
||||||
|
m_parentMainWindow->changeMade();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scene::addIC(QString filename)
|
||||||
|
{
|
||||||
|
// Set pos to center of user's view
|
||||||
|
QPointF gfxViewSceneCenter = m_parentGfxView->mapToScene(m_parentGfxView->viewport()->rect().center());
|
||||||
|
m_undoStack->push(new AddPart(this, PartType::IntegratedCircuit, gfxViewSceneCenter, filename));
|
||||||
|
m_parentMainWindow->changeMade();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scene::addPart(PartType::PartType partType)
|
||||||
|
{
|
||||||
|
// Set pos to center of user's view
|
||||||
|
QPointF gfxViewSceneCenter = m_parentGfxView->mapToScene(m_parentGfxView->viewport()->rect().center());
|
||||||
|
m_undoStack->push(new AddPart(this, partType, gfxViewSceneCenter));
|
||||||
|
m_parentMainWindow->changeMade();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scene::addWire(Connector* inputConnector, Connector* outputConnector)
|
||||||
|
{
|
||||||
|
m_undoStack->push(new AddWire(this, inputConnector, outputConnector));
|
||||||
|
|
||||||
|
m_parentMainWindow->changeMade();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scene::removeParts(const QList<Part*>& parts)
|
||||||
|
{
|
||||||
|
if(parts.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_undoStack->push(new RemoveParts(this, parts));
|
||||||
|
|
||||||
|
m_parentMainWindow->changeMade();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scene::removeWire(Wire* wire)
|
||||||
|
{
|
||||||
|
// Push wire into undo stack
|
||||||
|
m_undoStack->push(new RemoveWire(this, wire));
|
||||||
|
|
||||||
|
m_parentMainWindow->changeMade();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scene::moveParts(const QList<Part *>& parts, QPointF relPos)
|
||||||
|
{
|
||||||
|
m_undoStack->push(new MoveParts(this, parts, relPos));
|
||||||
|
|
||||||
|
for(auto part : parts)
|
||||||
|
{
|
||||||
|
part->m_oldPos = part->pos();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_parentMainWindow->changeMade();
|
||||||
|
}
|
||||||
|
|
||||||
|
// PRIVATE
|
||||||
|
|
||||||
|
void Scene::startTrackingPart(Part* part)
|
||||||
|
{
|
||||||
|
// Show part
|
||||||
|
part->show();
|
||||||
|
// Add part back into tracker list
|
||||||
|
m_logic->m_parts.append(part);
|
||||||
|
for(auto input : part->m_inputs)
|
||||||
|
// Add connector back into tracker list
|
||||||
|
m_logic->m_inputConnectors.append(input);
|
||||||
|
for(auto output : part->m_outputs)
|
||||||
|
// Add connector back into tracker list
|
||||||
|
m_logic->m_outputConnectors.append(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scene::stopTrackingPart(Part* part)
|
||||||
|
{
|
||||||
|
// Hide part
|
||||||
|
part->hide();
|
||||||
|
// Remove part from tracker list
|
||||||
|
m_logic->m_parts.removeOne(part);
|
||||||
|
for(auto input : part->m_inputs)
|
||||||
|
// Add connector from tracker list
|
||||||
|
m_logic->m_inputConnectors.removeOne(input);
|
||||||
|
for(auto output : part->m_outputs)
|
||||||
|
// Add connector from tracker list
|
||||||
|
m_logic->m_outputConnectors.removeOne(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scene::connectorClicked(Connector *connector)
|
||||||
|
{
|
||||||
|
if(m_parentMainWindow->toolMode == MainWindow::Disconnect)
|
||||||
|
{
|
||||||
|
removeConnectorsConnections(connector);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m_parentMainWindow->toolMode == MainWindow::Connect)
|
||||||
|
{
|
||||||
|
|
||||||
|
if(connector->m_connectorType == ConnectorType::Input)
|
||||||
|
{
|
||||||
|
// Toggle off if previous was clicked again
|
||||||
|
if(m_selectedInputConnector == connector)
|
||||||
|
{
|
||||||
|
m_selectedInputConnector->unselect();
|
||||||
|
m_selectedInputConnector = nullptr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Unselect previous if previous not nullptr
|
||||||
|
if(m_selectedInputConnector) m_selectedInputConnector->unselect();
|
||||||
|
// Update new connection
|
||||||
|
m_selectedInputConnector = connector;
|
||||||
|
connector->select();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
//Same stuff here, but with connectorSelectedRight instead of connectorSelectedLeft
|
||||||
|
{
|
||||||
|
if(m_selectedOutputConnector == connector)
|
||||||
|
{
|
||||||
|
m_selectedOutputConnector->unselect();
|
||||||
|
m_selectedOutputConnector = nullptr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(m_selectedOutputConnector) m_selectedOutputConnector->unselect();
|
||||||
|
m_selectedOutputConnector = connector;
|
||||||
|
connector->select();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If both sides now have a connector, add a wire
|
||||||
|
if(m_selectedInputConnector && m_selectedOutputConnector)
|
||||||
|
{
|
||||||
|
addWire(m_selectedOutputConnector, m_selectedInputConnector);
|
||||||
|
m_selectedInputConnector->unselect();
|
||||||
|
m_selectedInputConnector = nullptr;
|
||||||
|
m_selectedOutputConnector->unselect();
|
||||||
|
m_selectedOutputConnector = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scene::removeConnectorsConnections(Connector *connector)
|
||||||
|
{
|
||||||
|
// Remove wires
|
||||||
|
for(auto wire : connector->m_wires)
|
||||||
|
{
|
||||||
|
removeWire(wire);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
||||||
|
{
|
||||||
|
if (event->button() == Qt::LeftButton)
|
||||||
|
{
|
||||||
|
QList<QGraphicsItem*> movedItems = selectedItems();
|
||||||
|
if(!movedItems.isEmpty() && !(((Part*)movedItems[0])->pos() == ((Part*)movedItems[0])->m_oldPos))
|
||||||
|
{
|
||||||
|
QList<Part*> movedParts;
|
||||||
|
for(auto item : movedItems)
|
||||||
|
movedParts.append((Part*)item);
|
||||||
|
moveParts(movedParts, movedParts[0]->pos() - movedParts[0]->m_oldPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QGraphicsScene::mouseReleaseEvent(event);
|
||||||
|
}
|
95
Scene.h
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
#ifndef SCENE_H
|
||||||
|
#define SCENE_H
|
||||||
|
|
||||||
|
// The Scene class holds all important information to make a circuit work graphically.
|
||||||
|
// This includes things like undo, redo, etc...
|
||||||
|
|
||||||
|
#include <QGraphicsScene>
|
||||||
|
#include <QUndoStack>
|
||||||
|
|
||||||
|
#include "ePartType.h"
|
||||||
|
#include "CircuitBuffer.h"
|
||||||
|
|
||||||
|
#include "UndoCommands/CopyParts.h"
|
||||||
|
|
||||||
|
class MainWindow;
|
||||||
|
class Part;
|
||||||
|
class Wire;
|
||||||
|
class Connector;
|
||||||
|
|
||||||
|
class FileHandler;
|
||||||
|
class Logic;
|
||||||
|
|
||||||
|
class CopyParts;
|
||||||
|
|
||||||
|
class Scene : public QGraphicsScene
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
friend class Part;
|
||||||
|
friend class Wire;
|
||||||
|
friend class Connector;
|
||||||
|
friend class MainWindow;
|
||||||
|
|
||||||
|
friend class AddPart;
|
||||||
|
friend class RemoveParts;
|
||||||
|
friend class AddWire;
|
||||||
|
friend class RemoveWire;
|
||||||
|
friend class CopyParts;
|
||||||
|
friend class IntegratedCircuit;
|
||||||
|
|
||||||
|
friend class Logic;
|
||||||
|
|
||||||
|
friend class CircuitBuffer;
|
||||||
|
|
||||||
|
Scene(QGraphicsView *parentGfxView, MainWindow *parentMainWindow);
|
||||||
|
~Scene();
|
||||||
|
|
||||||
|
void updateGraphics();
|
||||||
|
|
||||||
|
void undo();
|
||||||
|
void redo();
|
||||||
|
|
||||||
|
// Initialized a Copy (only puts the parts into copy buffer)
|
||||||
|
void initCopy(const QList<Part*> &parts, const QList<Wire*> &wires);
|
||||||
|
// Does the copy using previously populated copy buffer (pastes parts from copy buffer)
|
||||||
|
void doCopy(bool relToMousePos = false);
|
||||||
|
|
||||||
|
// Adds an IC undoably
|
||||||
|
void addIC(QString filename);
|
||||||
|
// Adds part undoably
|
||||||
|
void addPart(PartType::PartType partType);
|
||||||
|
// Adds wire undoably
|
||||||
|
void addWire(Connector* inputConnector, Connector* outputConnector);
|
||||||
|
|
||||||
|
// Removes part undoably
|
||||||
|
void removeParts(const QList<Part*>& parts);
|
||||||
|
// Removes wire undoably
|
||||||
|
void removeWire(Wire* wire);
|
||||||
|
// Undoably moves parts
|
||||||
|
void moveParts(const QList<Part*>& parts, QPointF relPos);
|
||||||
|
|
||||||
|
private:
|
||||||
|
MainWindow *m_parentMainWindow;
|
||||||
|
QGraphicsView *m_parentGfxView;
|
||||||
|
|
||||||
|
Logic *m_logic;
|
||||||
|
|
||||||
|
QUndoStack *m_undoStack;
|
||||||
|
|
||||||
|
Connector* m_selectedInputConnector = nullptr;
|
||||||
|
Connector* m_selectedOutputConnector = nullptr;
|
||||||
|
|
||||||
|
CircuitBuffer m_copyBuffer;
|
||||||
|
|
||||||
|
void startTrackingPart(Part* part);
|
||||||
|
void stopTrackingPart(Part* part);
|
||||||
|
|
||||||
|
// Called by Connector when it is clicked, for example when creating or deleting wires
|
||||||
|
void connectorClicked(Connector *connector);
|
||||||
|
// Removal is done undoably
|
||||||
|
void removeConnectorsConnections(Connector *connector);
|
||||||
|
|
||||||
|
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SCENE_H
|
42
UndoCommands/AddPart.cpp
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#include "AddPart.h"
|
||||||
|
|
||||||
|
#include "RemoveWire.h"
|
||||||
|
|
||||||
|
#include "../Part.h"
|
||||||
|
#include "../Connector.h"
|
||||||
|
#include "../Scene.h"
|
||||||
|
#include "../Logic.h"
|
||||||
|
#include "../Parts/IntegratedCircuit.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
AddPart::AddPart(Scene* scene, PartType::PartType partType, QPointF pos, QString icFilename)
|
||||||
|
:m_scene(scene), m_partType(partType), m_pos(pos), m_icFilename(icFilename)
|
||||||
|
{
|
||||||
|
setText("Add Part");
|
||||||
|
}
|
||||||
|
|
||||||
|
AddPart::~AddPart()
|
||||||
|
{
|
||||||
|
m_scene->m_logic->deletePart(m_part);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddPart::redo()
|
||||||
|
{
|
||||||
|
if(!m_part)
|
||||||
|
{
|
||||||
|
if(m_partType == PartType::IntegratedCircuit)
|
||||||
|
m_part = m_scene->m_logic->createIC(m_icFilename, m_pos);
|
||||||
|
else
|
||||||
|
m_part = m_scene->m_logic->createPart(m_partType, m_pos);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_scene->startTrackingPart(m_part);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddPart::undo()
|
||||||
|
{
|
||||||
|
m_scene->stopTrackingPart(m_part);
|
||||||
|
}
|
30
UndoCommands/AddPart.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#ifndef ADDPART_H
|
||||||
|
#define ADDPART_H
|
||||||
|
|
||||||
|
#include <QUndoCommand>
|
||||||
|
#include <QPointF>
|
||||||
|
|
||||||
|
#include "../ePartType.h"
|
||||||
|
|
||||||
|
class Scene;
|
||||||
|
class Part;
|
||||||
|
class RemovePart;
|
||||||
|
|
||||||
|
class AddPart : public QUndoCommand
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AddPart(Scene* scene, PartType::PartType partType, QPointF pos, QString icFilename = "");
|
||||||
|
~AddPart();
|
||||||
|
|
||||||
|
void redo() override;
|
||||||
|
void undo() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Scene* m_scene;
|
||||||
|
Part* m_part = nullptr;
|
||||||
|
PartType::PartType m_partType;
|
||||||
|
QPointF m_pos;
|
||||||
|
QString m_icFilename;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ADDPART_H
|
26
UndoCommands/AddWire.cpp
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#include "AddWire.h"
|
||||||
|
|
||||||
|
#include "../Scene.h"
|
||||||
|
#include "../Logic.h"
|
||||||
|
#include "../Wire.h"
|
||||||
|
|
||||||
|
AddWire::AddWire(Scene* scene, Connector* connectorInput, Connector* connectorOutput)
|
||||||
|
:m_scene(scene), m_connectorInput(connectorInput), m_connectorOutput(connectorOutput)
|
||||||
|
{
|
||||||
|
setText("Add Wire");
|
||||||
|
}
|
||||||
|
|
||||||
|
AddWire::~AddWire()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AddWire::redo()
|
||||||
|
{
|
||||||
|
m_wire = m_scene->m_logic->createWire(m_connectorInput, m_connectorOutput);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddWire::undo()
|
||||||
|
{
|
||||||
|
m_scene->m_logic->deleteWire(m_wire);
|
||||||
|
}
|
26
UndoCommands/AddWire.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#ifndef ADDWIRE_H
|
||||||
|
#define ADDWIRE_H
|
||||||
|
|
||||||
|
#include <QUndoCommand>
|
||||||
|
|
||||||
|
class Scene;
|
||||||
|
class Wire;
|
||||||
|
class Connector;
|
||||||
|
|
||||||
|
class AddWire : public QUndoCommand
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AddWire(Scene* scene, Connector* connectorInput, Connector* connectorOutput);
|
||||||
|
~AddWire();
|
||||||
|
|
||||||
|
void redo() override;
|
||||||
|
void undo() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Scene* m_scene;
|
||||||
|
Wire* m_wire;
|
||||||
|
Connector* m_connectorInput;
|
||||||
|
Connector* m_connectorOutput;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ADDWIRE_H
|
59
UndoCommands/CopyParts.cpp
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
#include "CopyParts.h"
|
||||||
|
|
||||||
|
#include <QMap>
|
||||||
|
|
||||||
|
#include "../Scene.h"
|
||||||
|
#include "../Logic.h"
|
||||||
|
#include "../Part.h"
|
||||||
|
#include "../Connector.h"
|
||||||
|
#include "../CircuitBuffer.h"
|
||||||
|
|
||||||
|
#include "RemoveWire.h"
|
||||||
|
|
||||||
|
CopyParts::CopyParts(Scene* scene, const CircuitBuffer& toCopy, QPointF relPos)
|
||||||
|
:m_scene(scene), m_toCopy(toCopy), m_relPos(relPos), m_wireUndoStack(new QUndoStack)
|
||||||
|
{
|
||||||
|
setText("Copy Parts with offset " + QString::number(relPos.x()) + ", " + QString::number(relPos.y()));
|
||||||
|
}
|
||||||
|
|
||||||
|
CopyParts::~CopyParts()
|
||||||
|
{
|
||||||
|
for(auto part : m_copiedParts)
|
||||||
|
m_scene->m_logic->deletePart(part);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CopyParts::redo()
|
||||||
|
{
|
||||||
|
if(m_isFirstRedo)
|
||||||
|
{
|
||||||
|
m_isFirstRedo = false;
|
||||||
|
|
||||||
|
m_copiedParts = m_toCopy.addIntoScene(m_scene, m_relPos).first;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(auto part : m_copiedParts)
|
||||||
|
m_scene->startTrackingPart(part);
|
||||||
|
// Add wires back in
|
||||||
|
while(m_wireUndoStack->canUndo())
|
||||||
|
m_wireUndoStack->undo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CopyParts::undo()
|
||||||
|
{
|
||||||
|
for(auto part : m_copiedParts)
|
||||||
|
{
|
||||||
|
m_scene->stopTrackingPart(part);
|
||||||
|
for(auto input : part->m_inputs)
|
||||||
|
{
|
||||||
|
for(auto wire : input->m_wires)
|
||||||
|
m_wireUndoStack->push(new RemoveWire(m_scene, wire));
|
||||||
|
}
|
||||||
|
for(auto output : part->m_outputs)
|
||||||
|
{
|
||||||
|
for(auto wire : output->m_wires)
|
||||||
|
m_wireUndoStack->push(new RemoveWire(m_scene, wire));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
43
UndoCommands/CopyParts.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#ifndef COPYPARTS_H
|
||||||
|
#define COPYPARTS_H
|
||||||
|
|
||||||
|
#include <QUndoStack>
|
||||||
|
#include <QUndoCommand>
|
||||||
|
#include <QList>
|
||||||
|
#include <QPointF>
|
||||||
|
|
||||||
|
#include "../ePartType.h"
|
||||||
|
|
||||||
|
class Scene;
|
||||||
|
class Part;
|
||||||
|
class Wire;
|
||||||
|
|
||||||
|
class CircuitBuffer;
|
||||||
|
|
||||||
|
class CopyParts : public QUndoCommand
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef QPair<PartType::PartType, QPointF> PartData;
|
||||||
|
typedef QPair<PartData*, PartData*> WireData;
|
||||||
|
|
||||||
|
friend class Scene;
|
||||||
|
|
||||||
|
CopyParts(Scene* scene, const CircuitBuffer& toCopy, QPointF relPos);
|
||||||
|
~CopyParts();
|
||||||
|
|
||||||
|
void redo() override;
|
||||||
|
void undo() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Scene* m_scene;
|
||||||
|
// Since m_toCopy get used immediately, there shouldn't be any segfaults due to any parts that have changed
|
||||||
|
const CircuitBuffer& m_toCopy;
|
||||||
|
QList<Part*> m_copiedParts;
|
||||||
|
QPointF m_relPos;
|
||||||
|
|
||||||
|
bool m_isFirstRedo = true;
|
||||||
|
|
||||||
|
QUndoStack* m_wireUndoStack;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // COPYPARTS_H
|
31
UndoCommands/MoveParts.cpp
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#include "MoveParts.h"
|
||||||
|
|
||||||
|
#include "../Part.h"
|
||||||
|
|
||||||
|
MoveParts::MoveParts(Scene* scene, const QList<Part*>& parts, QPointF relPos)
|
||||||
|
:m_scene(scene), m_parts(parts), m_relPos(relPos)
|
||||||
|
{
|
||||||
|
setText("Move parts by " + QString::number(relPos.x()) + ", " + QString::number(relPos.y()));
|
||||||
|
}
|
||||||
|
|
||||||
|
MoveParts::~MoveParts()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void MoveParts::redo()
|
||||||
|
{
|
||||||
|
if(m_isFirstRedo)
|
||||||
|
m_isFirstRedo = false;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(auto part : m_parts)
|
||||||
|
part->moveBy(m_relPos.x(), m_relPos.y());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MoveParts::undo()
|
||||||
|
{
|
||||||
|
for(auto part : m_parts)
|
||||||
|
part->moveBy(-m_relPos.x(), -m_relPos.y());
|
||||||
|
}
|
27
UndoCommands/MoveParts.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#ifndef MOVEPARTS_H
|
||||||
|
#define MOVEPARTS_H
|
||||||
|
|
||||||
|
#include <QUndoCommand>
|
||||||
|
#include <QPointF>
|
||||||
|
|
||||||
|
class Scene;
|
||||||
|
class Part;
|
||||||
|
|
||||||
|
class MoveParts : public QUndoCommand
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MoveParts(Scene* scene, const QList<Part*>& parts, QPointF relPos);
|
||||||
|
~MoveParts();
|
||||||
|
|
||||||
|
void redo() override;
|
||||||
|
void undo() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Scene* m_scene;
|
||||||
|
QList<Part*> m_parts;
|
||||||
|
QPointF m_relPos;
|
||||||
|
|
||||||
|
bool m_isFirstRedo = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MOVEPARTS_H
|
52
UndoCommands/RemoveParts.cpp
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
#include "RemoveParts.h"
|
||||||
|
|
||||||
|
#include "../Scene.h"
|
||||||
|
#include "../Part.h"
|
||||||
|
#include "../Connector.h"
|
||||||
|
#include "../Logic.h"
|
||||||
|
#include "RemoveWire.h"
|
||||||
|
|
||||||
|
RemoveParts::RemoveParts(Scene* scene, const QList<Part*>& parts)
|
||||||
|
:m_scene(scene), m_parts(parts), m_wireUndoStack(new QUndoStack)
|
||||||
|
{
|
||||||
|
setText("Remove Parts");
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoveParts::~RemoveParts()
|
||||||
|
{
|
||||||
|
for(auto part : m_parts)
|
||||||
|
m_scene->m_logic->deletePart(part);
|
||||||
|
delete m_wireUndoStack;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoveParts::redo()
|
||||||
|
{
|
||||||
|
for(auto part : m_parts)
|
||||||
|
{
|
||||||
|
for(auto input : part->m_inputs)
|
||||||
|
{
|
||||||
|
for(auto wire : input->m_wires)
|
||||||
|
// Remove wire
|
||||||
|
m_wireUndoStack->push(new RemoveWire(m_scene, wire));
|
||||||
|
}
|
||||||
|
for(auto output : part->m_outputs)
|
||||||
|
{
|
||||||
|
for(auto wire : output->m_wires)
|
||||||
|
// Remove wire
|
||||||
|
m_wireUndoStack->push(new RemoveWire(m_scene, wire));
|
||||||
|
}
|
||||||
|
m_scene->stopTrackingPart(part);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoveParts::undo()
|
||||||
|
{
|
||||||
|
for(auto part : m_parts)
|
||||||
|
{
|
||||||
|
m_scene->startTrackingPart(part);
|
||||||
|
|
||||||
|
// Add wires back in
|
||||||
|
while(m_wireUndoStack->canUndo())
|
||||||
|
m_wireUndoStack->undo();
|
||||||
|
}
|
||||||
|
}
|
27
UndoCommands/RemoveParts.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#ifndef REMOVEPARTS_H
|
||||||
|
#define REMOVEPARTS_H
|
||||||
|
|
||||||
|
#include <QUndoCommand>
|
||||||
|
#include <QList>
|
||||||
|
|
||||||
|
class Scene;
|
||||||
|
class Part;
|
||||||
|
class Connector;
|
||||||
|
|
||||||
|
class RemoveParts : public QUndoCommand
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RemoveParts(Scene* scene, const QList<Part*>& parts);
|
||||||
|
~RemoveParts();
|
||||||
|
|
||||||
|
void redo() override;
|
||||||
|
void undo() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Scene* m_scene;
|
||||||
|
QList<Part*> m_parts;
|
||||||
|
|
||||||
|
QUndoStack* m_wireUndoStack;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // REMOVEPARTS_H
|
36
UndoCommands/RemoveWire.cpp
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#include "RemoveWire.h"
|
||||||
|
|
||||||
|
#include "../Scene.h"
|
||||||
|
#include "../Logic.h"
|
||||||
|
#include "../Wire.h"
|
||||||
|
#include "../Part.h"
|
||||||
|
#include "../Connector.h"
|
||||||
|
|
||||||
|
RemoveWire::RemoveWire(Scene* scene, Wire* wire)
|
||||||
|
:m_scene(scene), m_wire(wire)
|
||||||
|
{
|
||||||
|
setText("Remove Wire");
|
||||||
|
|
||||||
|
m_wireInputPart = (Part*)wire->m_connectorInput->parentItem();
|
||||||
|
m_wireInputConnectorIdx = m_wireInputPart->m_outputs.indexOf(wire->m_connectorInput);
|
||||||
|
|
||||||
|
m_wireOutputPart = (Part*)wire->m_connectorOutput->parentItem();
|
||||||
|
m_wireOutputConnectorIdx = m_wireOutputPart->m_inputs.indexOf(wire->m_connectorOutput);
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoveWire::~RemoveWire()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoveWire::redo()
|
||||||
|
{
|
||||||
|
m_scene->m_logic->deleteWire(m_wire);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RemoveWire::undo()
|
||||||
|
{
|
||||||
|
Connector* inputConnector = m_wireInputPart->m_outputs[m_wireInputConnectorIdx];
|
||||||
|
Connector* outputConnector = m_wireOutputPart->m_inputs[m_wireOutputConnectorIdx];
|
||||||
|
m_wire = m_scene->m_logic->createWire(inputConnector, outputConnector);
|
||||||
|
}
|
28
UndoCommands/RemoveWire.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#ifndef REMOVEWIRE_H
|
||||||
|
#define REMOVEWIRE_H
|
||||||
|
|
||||||
|
#include <QUndoCommand>
|
||||||
|
|
||||||
|
class Scene;
|
||||||
|
class Wire;
|
||||||
|
class Part;
|
||||||
|
|
||||||
|
class RemoveWire : public QUndoCommand
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RemoveWire(Scene* scene, Wire* wire);
|
||||||
|
~RemoveWire();
|
||||||
|
|
||||||
|
void redo() override;
|
||||||
|
void undo() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Scene* m_scene;
|
||||||
|
Wire* m_wire;
|
||||||
|
Part* m_wireInputPart;
|
||||||
|
int m_wireInputConnectorIdx;
|
||||||
|
Part* m_wireOutputPart;
|
||||||
|
int m_wireOutputConnectorIdx;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // REMOVEWIRE_H
|
48
Wire.cpp
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#include "Wire.h"
|
||||||
|
|
||||||
|
#include <QPainter>
|
||||||
|
#include <qdebug.h>
|
||||||
|
#include "Connector.h"
|
||||||
|
#include "eConnectorType.h"
|
||||||
|
|
||||||
|
Wire::Wire(Scene* scene, Connector *A, Connector *B)
|
||||||
|
:m_scene(scene)
|
||||||
|
{
|
||||||
|
if(A->connectorType() == B->connectorType())
|
||||||
|
{
|
||||||
|
qFatal("Instance CircuitWire cannot connect two CircuitConnectors which are on the same side of a CircuitItem");
|
||||||
|
}
|
||||||
|
if(A->connectorType() == ConnectorType::Output)
|
||||||
|
{
|
||||||
|
m_connectorInput = A;
|
||||||
|
m_connectorOutput = B;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_connectorInput = B;
|
||||||
|
m_connectorOutput = A;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Wire::updateLine()
|
||||||
|
{
|
||||||
|
QPointF posI = m_connectorInput->scenePos();
|
||||||
|
QPointF posO = m_connectorOutput->scenePos();
|
||||||
|
setLine(posI.x() + 11.f, posI.y(), posO.x() - 11.f, posO.y());
|
||||||
|
QPen p;
|
||||||
|
p.setWidth(2);
|
||||||
|
if(m_state)
|
||||||
|
p.setColor(Qt::GlobalColor::green);
|
||||||
|
setPen(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Wire::feedInput()
|
||||||
|
{
|
||||||
|
// Update output state
|
||||||
|
//m_connectorOutput->m_state = true;
|
||||||
|
m_connectorOutput->m_state = (m_connectorOutput->m_state || m_connectorInput->m_state);
|
||||||
|
// Update own state
|
||||||
|
m_state = m_connectorInput->m_state;
|
||||||
|
}
|
38
Wire.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#ifndef CIRCUITWIRE_H
|
||||||
|
#define CIRCUITWIRE_H
|
||||||
|
|
||||||
|
#include <QGraphicsLineItem>
|
||||||
|
|
||||||
|
class Connector;
|
||||||
|
class Scene;
|
||||||
|
|
||||||
|
class Wire : public QGraphicsLineItem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
friend class Connector;
|
||||||
|
friend class Scene;
|
||||||
|
friend class Logic;
|
||||||
|
|
||||||
|
friend class RemoveWire;
|
||||||
|
|
||||||
|
friend class MainWindow;
|
||||||
|
|
||||||
|
friend class FileHandler;
|
||||||
|
|
||||||
|
friend class CircuitBuffer;
|
||||||
|
|
||||||
|
// Assumes that the CircuitConnectors A and B each have a different orientation
|
||||||
|
Wire(Scene* scene, Connector *A, Connector *B);
|
||||||
|
|
||||||
|
void updateLine(); // Graphical update
|
||||||
|
void feedInput(); // Logical update (feeds input to output and updates state, also causes a graphical update)
|
||||||
|
private:
|
||||||
|
Scene* m_scene;
|
||||||
|
|
||||||
|
Connector* m_connectorInput; // connector inputting to this wire
|
||||||
|
Connector* m_connectorOutput; // connector receiving output from this wire
|
||||||
|
|
||||||
|
bool m_state = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CIRCUITWIRE_H
|
13
eConnectorType.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#ifndef CONNECTORTYPE_H
|
||||||
|
#define CONNECTORTYPE_H
|
||||||
|
|
||||||
|
namespace ConnectorType
|
||||||
|
{
|
||||||
|
enum ConnectorType
|
||||||
|
{
|
||||||
|
Input,
|
||||||
|
Output
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CONNECTORTYPE_H
|
24
ePartType.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#ifndef EPARTTYPE_H
|
||||||
|
#define EPARTTYPE_H
|
||||||
|
|
||||||
|
namespace PartType
|
||||||
|
{
|
||||||
|
enum PartType
|
||||||
|
{
|
||||||
|
GateBuffer,
|
||||||
|
GateNot,
|
||||||
|
GateAnd,
|
||||||
|
GateOr,
|
||||||
|
GateNand,
|
||||||
|
GateNor,
|
||||||
|
GateXor,
|
||||||
|
GateXnor,
|
||||||
|
IOLowConstant,
|
||||||
|
IOHighConstant,
|
||||||
|
IOLightBulb,
|
||||||
|
IOToggleButton,
|
||||||
|
IntegratedCircuit,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // EPARTTYPE_H
|