File indexing completed on 2024-05-05 05:46:07

0001 /***************************************************************************
0002  *   Copyright (C) 2004-2006 by David Saxton                               *
0003  *   david@bluehaze.org                                                    *
0004  *                                                                         *
0005  *   This program is free software; you can redistribute it and/or modify  *
0006  *   it under the terms of the GNU General Public License as published by  *
0007  *   the Free Software Foundation; either version 2 of the License, or     *
0008  *   (at your option) any later version.                                   *
0009  ***************************************************************************/
0010 
0011 #include "multiinputgate.h"
0012 #include "ecnode.h"
0013 #include "icndocument.h"
0014 #include "libraryitem.h"
0015 #include "logic.h"
0016 
0017 #include <KLocalizedString>
0018 #include <QPainter>
0019 #include <cmath>
0020 
0021 #include <algorithm>
0022 
0023 #include <ktlconfig.h>
0024 
0025 // BEGIN class MultiInputGate
0026 
0027 void MultiInputGate_inStateChanged(void *objV, bool state) { // Enable
0028     MultiInputGate *objT = static_cast<MultiInputGate*>(objV);
0029     objT->inStateChanged(state);
0030 }
0031 
0032 MultiInputGate::MultiInputGate(ICNDocument *icnDocument, bool newItem, const char *id, const QString &rectangularShapeText, bool invertedOutput, int baseWidth, bool likeOR)
0033     : Component(icnDocument, newItem, id)
0034 {
0035     m_bLikeOR = likeOR;
0036     m_bDoneInit = false;
0037     m_numInputs = 0;
0038     m_distinctiveWidth = baseWidth;
0039     m_bInvertedOutput = invertedOutput;
0040     m_rectangularShapeText = rectangularShapeText;
0041 
0042     for (int i = 0; i < maxGateInput; ++i) {
0043         inLogic[i] = nullptr;
0044         inNode[i] = nullptr;
0045     }
0046 
0047     updateLogicSymbolShape();
0048 
0049     updateInputs(2);
0050 
0051     init1PinRight(16);
0052     m_pOut = createLogicOut(m_pPNode[0], false);
0053 
0054     createProperty("numInput", Variant::Type::Int);
0055     property("numInput")->setCaption(i18n("Number Inputs"));
0056     property("numInput")->setMinValue(2);
0057     property("numInput")->setMaxValue(maxGateInput);
0058     property("numInput")->setValue(2);
0059 
0060     m_bDoneInit = true;
0061 }
0062 
0063 MultiInputGate::~MultiInputGate()
0064 {
0065 }
0066 
0067 void MultiInputGate::slotUpdateConfiguration()
0068 {
0069     updateLogicSymbolShape();
0070     Component::slotUpdateConfiguration();
0071 }
0072 
0073 void MultiInputGate::updateLogicSymbolShape()
0074 {
0075     // Set the canvas changed for the old shape
0076     setChanged();
0077 
0078     if (KTLConfig::logicSymbolShapes() == KTLConfig::EnumLogicSymbolShapes::Distinctive) {
0079         m_logicSymbolShape = Distinctive;
0080         setSize(-m_distinctiveWidth / 2, offsetY(), m_distinctiveWidth, height(), true);
0081     } else {
0082         m_logicSymbolShape = Rectangular;
0083         setSize(-16, offsetY(), 32, height(), true);
0084     }
0085 
0086     updateSymbolText();
0087     updateAttachedPositioning();
0088     if (p_itemDocument)
0089         p_itemDocument->requestEvent(ItemDocument::ItemDocumentEvent::RerouteInvalidatedConnectors);
0090 
0091     // Set the canvas changed for the new shape
0092     setChanged();
0093 }
0094 
0095 void MultiInputGate::updateSymbolText()
0096 {
0097     if (m_logicSymbolShape == Distinctive)
0098         removeDisplayText("rect-shape-text");
0099     else {
0100         int w = 32 - (m_bInvertedOutput ? 6 : 0);
0101         QRect r(-16, 4 - height() / 2, w, height() - 4);
0102         addDisplayText("rect-shape-text", r, m_rectangularShapeText, true, Qt::AlignTop | Qt::AlignHCenter);
0103     }
0104 }
0105 
0106 int MultiInputGate::logicSymbolShapeToWidth() const
0107 {
0108     return (m_logicSymbolShape == Distinctive) ? m_distinctiveWidth : 32;
0109 }
0110 
0111 void MultiInputGate::dataChanged()
0112 {
0113     updateInputs(std::min(maxGateInput, dataInt("numInput")));
0114 }
0115 
0116 void MultiInputGate::updateInputs(int newNum)
0117 {
0118     if (newNum == m_numInputs)
0119         return;
0120 
0121     if (newNum < 2)
0122         newNum = 2;
0123     else if (newNum > maxGateInput)
0124         newNum = maxGateInput;
0125 
0126     int newWidth = logicSymbolShapeToWidth();
0127 
0128     QRect r(-newWidth / 2, -8 * newNum, newWidth, 16 * newNum);
0129     setSize(r, true);
0130     updateSymbolText();
0131 
0132     const bool added = (newNum > m_numInputs);
0133     if (added) {
0134         for (int i = m_numInputs; i < newNum; ++i) {
0135             ECNode *node = createPin(0, 0, 0, "in" + QString::number(i));
0136             inNode[i] = node;
0137             inLogic[i] = createLogicIn(node);
0138             //inLogic[i]->setCallback(this, (CallbackPtr)(&MultiInputGate::inStateChanged));
0139             inLogic[i]->setCallback2(MultiInputGate_inStateChanged, this);
0140         }
0141     } else {
0142         for (int i = newNum; i < m_numInputs; ++i) {
0143             removeNode("in" + QString::number(i));
0144             removeElement(inLogic[i], false);
0145             inNode[i] = nullptr;
0146             inLogic[i] = nullptr;
0147         }
0148     }
0149 
0150     m_numInputs = newNum;
0151 
0152     // We can't call a pure-virtual function if we haven't finished our constructor yet...
0153     if (m_bDoneInit)
0154         inStateChanged(!added);
0155 
0156     updateAttachedPositioning();
0157 }
0158 
0159 void MultiInputGate::updateAttachedPositioning()
0160 {
0161     // Check that our ndoes have been created before we attempt to use them
0162     if (!m_nodeMap.contains("p1") || !m_nodeMap.contains("in" + QString::number(m_numInputs - 1)))
0163         return;
0164 
0165     int _x = offsetX() + 8;
0166     int _y = offsetY() + 8;
0167 
0168     m_nodeMap["p1"].x = logicSymbolShapeToWidth() / 2 + 8;
0169     m_nodeMap["p1"].y = 0;
0170 
0171     int n = m_numInputs;
0172 
0173     for (int i = 0; i < n; ++i) {
0174         m_nodeMap["in" + QString::number(i)].x = _x - 16;
0175         m_nodeMap["in" + QString::number(i)].y = _y + 16 * i;
0176 
0177         // The curvy part at the base of OR-like logic gates means that the
0178         // input needs need to be increased in length
0179         if (m_bLikeOR) {
0180             int length = 8;
0181             if (m_logicSymbolShape == Distinctive) {
0182                 length += int(std::sqrt(double(64 * n * n - (8 * n - 8 - 16 * i) * (8 * n - 8 - 16 * i)))) / n;
0183             }
0184             inNode[i]->setLength(length);
0185         }
0186     }
0187 
0188     if (m_bDoneInit)
0189         Component::updateAttachedPositioning();
0190 }
0191 
0192 void MultiInputGate::drawShape(QPainter &p)
0193 {
0194     initPainter(p);
0195 
0196     int _x = int(x() + offsetX());
0197     int _y = int(y() + offsetY());
0198 
0199     if (m_bInvertedOutput) {
0200         p.drawRect(_x, _y, 32 - 6, height());
0201         p.drawEllipse(_x + 32 - 6, int(y()) - 3, 6, 6);
0202     } else {
0203         p.drawRect(_x, _y, 32, height());
0204     }
0205 
0206     deinitPainter(p);
0207 }
0208 // END class MultiInputGate
0209 
0210 // BEGIN class ECXNor
0211 Item *ECXnor::construct(ItemDocument *itemDocument, bool newItem, const char *id)
0212 {
0213     return new ECXnor(static_cast<ICNDocument *>(itemDocument), newItem, id);
0214 }
0215 
0216 LibraryItem *ECXnor::libraryItem()
0217 {
0218     return new LibraryItem(QStringList(QString("ec/xnor")), i18n("XNOR gate"), i18n("Logic"), "xnor.png", LibraryItem::lit_component, ECXnor::construct);
0219 }
0220 
0221 ECXnor::ECXnor(ICNDocument *icnDocument, bool newItem, const char *id)
0222     : MultiInputGate(icnDocument, newItem, id ? id : "xnor", "=1", true, 48, true)
0223 {
0224     m_name = i18n("XNOR gate");
0225 
0226     inStateChanged(false);
0227 }
0228 
0229 ECXnor::~ECXnor()
0230 {
0231 }
0232 
0233 void ECXnor::inStateChanged(bool)
0234 {
0235     int highCount = 0;
0236     for (int i = 0; i < m_numInputs; ++i) {
0237         if (inLogic[i]->isHigh())
0238             highCount++;
0239     }
0240 
0241     m_pOut->setHigh(highCount != 1);
0242 }
0243 
0244 void ECXnor::drawShape(QPainter &p)
0245 {
0246     if (m_logicSymbolShape == Rectangular) {
0247         MultiInputGate::drawShape(p);
0248         return;
0249     }
0250 
0251     initPainter(p);
0252     int _x = int(x()) + offsetX();
0253     int _y = int(y()) + offsetY();
0254 
0255     p.save();
0256     p.setPen(Qt::NoPen);
0257     p.drawChord(_x - width() + 22, _y, 2 * width() - 28, height(), -16 * 81, 16 * 162);
0258     p.restore();
0259 
0260     p.drawArc(_x - width() + 22, _y, 2 * width() - 28, height(), -16 * 90, 16 * 180);
0261     p.drawArc(_x - 8, _y, 16, height(), -16 * 90, 16 * 180);
0262     p.drawArc(_x, _y, 16, height(), -16 * 90, 16 * 180);
0263 
0264     p.drawEllipse(_x + width() - 6, _y + (height() / 2) - 3, 6, 6);
0265 
0266     deinitPainter(p);
0267 }
0268 // END class ECXnor
0269 
0270 // BEGIN class ECXor
0271 Item *ECXor::construct(ItemDocument *itemDocument, bool newItem, const char *id)
0272 {
0273     return new ECXor(static_cast<ICNDocument *>(itemDocument), newItem, id);
0274 }
0275 
0276 LibraryItem *ECXor::libraryItem()
0277 {
0278     return new LibraryItem(QStringList(QString("ec/xor")), i18n("XOR gate"), i18n("Logic"), "xor.png", LibraryItem::lit_component, ECXor::construct);
0279 }
0280 
0281 ECXor::ECXor(ICNDocument *icnDocument, bool newItem, const char *id)
0282     : MultiInputGate(icnDocument, newItem, id ? id : "xor", "=1", false, 48, true)
0283 {
0284     m_name = i18n("XOR gate");
0285 
0286     inStateChanged(false);
0287 }
0288 
0289 ECXor::~ECXor()
0290 {
0291 }
0292 
0293 void ECXor::inStateChanged(bool)
0294 {
0295     int highCount = 0;
0296     for (int i = 0; i < m_numInputs; ++i) {
0297         if (inLogic[i]->isHigh())
0298             highCount++;
0299     }
0300 
0301     m_pOut->setHigh(highCount == 1);
0302 }
0303 
0304 void ECXor::drawShape(QPainter &p)
0305 {
0306     if (m_logicSymbolShape == Rectangular) {
0307         MultiInputGate::drawShape(p);
0308         return;
0309     }
0310 
0311     initPainter(p);
0312     int _x = int(x()) + offsetX();
0313     int _y = int(y()) + offsetY();
0314 
0315     p.save();
0316     p.setPen(Qt::NoPen);
0317     p.drawChord(_x - width() + 16, _y, 2 * width() - 16, height(), -16 * 81, 16 * 162);
0318     p.restore();
0319 
0320     p.drawArc(_x - width() + 16, _y, 2 * width() - 16, height(), -16 * 90, 16 * 180);
0321     p.drawArc(_x - 8, _y, 16, height(), -16 * 90, 16 * 180);
0322     p.drawArc(_x, _y, 16, height(), -16 * 90, 16 * 180);
0323 
0324     deinitPainter(p);
0325 }
0326 // END class ECXor
0327 
0328 // BEGIN class ECOr
0329 Item *ECOr::construct(ItemDocument *itemDocument, bool newItem, const char *id)
0330 {
0331     return new ECOr(static_cast<ICNDocument *>(itemDocument), newItem, id);
0332 }
0333 
0334 LibraryItem *ECOr::libraryItem()
0335 {
0336     return new LibraryItem(QStringList(QString("ec/or")), i18n("OR gate"), i18n("Logic"), "or.png", LibraryItem::lit_component, ECOr::construct);
0337 }
0338 
0339 ECOr::ECOr(ICNDocument *icnDocument, bool newItem, const char *id)
0340     : MultiInputGate(icnDocument, newItem, id ? id : "or", QChar(0x2265) + QString("1"), false, 48, true)
0341 {
0342     m_name = i18n("OR gate");
0343 
0344     inStateChanged(false);
0345 }
0346 
0347 ECOr::~ECOr()
0348 {
0349 }
0350 
0351 void ECOr::inStateChanged(bool)
0352 {
0353     bool allLow = true;
0354     for (int i = 0; i < m_numInputs && allLow; ++i) {
0355         if (inLogic[i]->isHigh())
0356             allLow = false;
0357     }
0358 
0359     m_pOut->setHigh(!allLow);
0360 }
0361 
0362 void ECOr::drawShape(QPainter &p)
0363 {
0364     if (m_logicSymbolShape == Rectangular) {
0365         MultiInputGate::drawShape(p);
0366         return;
0367     }
0368 
0369     initPainter(p);
0370     int _x = int(x()) + offsetX();
0371     int _y = int(y()) + offsetY();
0372 
0373     p.save();
0374     p.setPen(Qt::NoPen);
0375     //  p.setBrush( Qt::red );
0376     p.drawChord(_x - width(), _y, 2 * width(), height(), -16 * 81, 16 * 162);
0377     //  p.drawPie( _x-width()+16, _y, 2*width()-16, height(), -16*100, 16*200 );
0378     p.restore();
0379 
0380     p.drawArc(_x - width(), _y, 2 * width(), height(), -16 * 90, 16 * 180);
0381     p.drawArc(_x - 8, _y, 16, height(), -16 * 90, 16 * 180);
0382 
0383     deinitPainter(p);
0384 }
0385 // END class ECOr
0386 
0387 // BEGIN class ECNor
0388 Item *ECNor::construct(ItemDocument *itemDocument, bool newItem, const char *id)
0389 {
0390     return new ECNor(static_cast<ICNDocument *>(itemDocument), newItem, id);
0391 }
0392 
0393 LibraryItem *ECNor::libraryItem()
0394 {
0395     return new LibraryItem(QStringList(QString("ec/nor")), i18n("NOR gate"), i18n("Logic"), "nor.png", LibraryItem::lit_component, ECNor::construct);
0396 }
0397 
0398 ECNor::ECNor(ICNDocument *icnDocument, bool newItem, const char *id)
0399     : MultiInputGate(icnDocument, newItem, id ? id : "nor", QChar(0x2265) + QString("1"), true, 48, true)
0400 {
0401     m_name = i18n("NOR Gate");
0402 
0403     inStateChanged(false);
0404 }
0405 
0406 ECNor::~ECNor()
0407 {
0408 }
0409 
0410 void ECNor::inStateChanged(bool)
0411 {
0412     bool allLow = true;
0413     for (int i = 0; i < m_numInputs && allLow; ++i) {
0414         if (inLogic[i]->isHigh())
0415             allLow = false;
0416     }
0417 
0418     m_pOut->setHigh(allLow);
0419 }
0420 
0421 void ECNor::drawShape(QPainter &p)
0422 {
0423     if (m_logicSymbolShape == Rectangular) {
0424         MultiInputGate::drawShape(p);
0425         return;
0426     }
0427 
0428     initPainter(p);
0429     int _x = int(x()) + offsetX();
0430     int _y = int(y()) + offsetY();
0431 
0432     p.save();
0433     p.setPen(Qt::NoPen);
0434     p.drawChord(_x - width() + 6, _y, 2 * width() - 12, height(), -16 * 81, 16 * 162);
0435     p.restore();
0436 
0437     p.drawArc(_x - width() + 6, _y, 2 * width() - 12, height(), -16 * 90, 16 * 180);
0438     p.drawArc(_x - 8, _y, 16, height(), -16 * 90, 16 * 180);
0439 
0440     p.drawEllipse(_x + width() - 6, _y + (height() / 2) - 3, 6, 6);
0441 
0442     deinitPainter(p);
0443 }
0444 // END class ECNor
0445 
0446 // BEGIN class ECNand
0447 Item *ECNand::construct(ItemDocument *itemDocument, bool newItem, const char *id)
0448 {
0449     return new ECNand(static_cast<ICNDocument *>(itemDocument), newItem, id);
0450 }
0451 
0452 LibraryItem *ECNand::libraryItem()
0453 {
0454     return new LibraryItem(QStringList(QString("ec/nand")), i18n("NAND gate"), i18n("Logic"), "nand.png", LibraryItem::lit_component, ECNand::construct);
0455 }
0456 
0457 ECNand::ECNand(ICNDocument *icnDocument, bool newItem, const char *id)
0458     : MultiInputGate(icnDocument, newItem, id ? id : "nand", "&", true, 32, false)
0459 {
0460     m_name = i18n("NAND Gate");
0461 
0462     inStateChanged(false);
0463 }
0464 
0465 ECNand::~ECNand()
0466 {
0467 }
0468 
0469 void ECNand::inStateChanged(bool)
0470 {
0471     for (int i = 0; i < m_numInputs; ++i) {
0472         if (!inLogic[i]->isHigh()) {
0473             m_pOut->setHigh(true);
0474             return;
0475         }
0476     }
0477 
0478     m_pOut->setHigh(false);
0479 }
0480 
0481 void ECNand::drawShape(QPainter &p)
0482 {
0483     if (m_logicSymbolShape == Rectangular) {
0484         MultiInputGate::drawShape(p);
0485         return;
0486     }
0487 
0488     initPainter(p);
0489     int _x = int(x()) + offsetX();
0490     int _y = int(y()) + offsetY();
0491     p.drawChord(_x - width() + 6, _y, 2 * width() - 12, height(), -16 * 90, 16 * 180);
0492     p.drawEllipse(_x + width() - 6, _y + (height() / 2) - 3, 6, 6);
0493     deinitPainter(p);
0494 }
0495 // END class ECNand
0496 
0497 // BEGIN class ECAnd
0498 Item *ECAnd::construct(ItemDocument *itemDocument, bool newItem, const char *id)
0499 {
0500     return new ECAnd(static_cast<ICNDocument *>(itemDocument), newItem, id);
0501 }
0502 
0503 LibraryItem *ECAnd::libraryItem()
0504 {
0505     QStringList idList;
0506     idList << "ec/and"
0507            << "ec/and_2";
0508     return new LibraryItem(idList, i18n("AND gate"), i18n("Logic"), "and.png", LibraryItem::lit_component, ECAnd::construct);
0509 }
0510 
0511 ECAnd::ECAnd(ICNDocument *icnDocument, bool newItem, const char *id)
0512     : MultiInputGate(icnDocument, newItem, id ? id : "and", "&", false, 32, false)
0513 {
0514     m_name = i18n("AND Gate");
0515 
0516     inStateChanged(false);
0517 }
0518 
0519 ECAnd::~ECAnd()
0520 {
0521 }
0522 
0523 void ECAnd::inStateChanged(bool)
0524 {
0525     for (int i = 0; i < m_numInputs; ++i) {
0526         if (!inLogic[i]->isHigh()) {
0527             m_pOut->setHigh(false);
0528             return;
0529         }
0530     }
0531 
0532     m_pOut->setHigh(true);
0533 }
0534 
0535 void ECAnd::drawShape(QPainter &p)
0536 {
0537     if (m_logicSymbolShape == Rectangular) {
0538         MultiInputGate::drawShape(p);
0539         return;
0540     }
0541 
0542     initPainter(p);
0543 
0544     int _x = int(x()) + offsetX();
0545     int _y = int(y()) + offsetY();
0546 
0547     p.drawChord(_x - width(), _y, 2 * width(), height(), -16 * 90, 16 * 180);
0548 
0549     deinitPainter(p);
0550 }
0551 // END class ECAnd