File indexing completed on 2024-05-19 09:39: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