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
|