diff --git a/resources/properties.xml b/resources/properties.xml index f85d65b19..fdc24308a 100644 --- a/resources/properties.xml +++ b/resources/properties.xml @@ -276,6 +276,7 @@ + @@ -315,4 +316,16 @@ + + + + + + + + + + + + diff --git a/src/infoview/htmlinfoview.cpp b/src/infoview/htmlinfoview.cpp index d7e5c7b68..a33815c7a 100644 --- a/src/infoview/htmlinfoview.cpp +++ b/src/infoview/htmlinfoview.cpp @@ -285,6 +285,7 @@ void HtmlInfoView::init(bool tinyMode) { m_spiceTextLabel = new TagLabel(this); m_spiceTextLabel->setWordWrap(true); m_spiceTextLabel->setObjectName("tagsValue"); + m_spiceTextLabel->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse); vlo->addWidget(m_spiceTextLabel); m_tagLabel = new QLabel(tr("Tags"), NULL); @@ -295,6 +296,7 @@ void HtmlInfoView::init(bool tinyMode) { m_tagsTextLabel = new TagLabel(this); m_tagsTextLabel->setWordWrap(true); m_tagsTextLabel->setObjectName("tagsValue"); + m_tagsTextLabel->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse); vlo->addWidget(m_tagsTextLabel); if (tinyMode) m_tagsTextLabel->setVisible(false); diff --git a/src/items/capacitor.cpp b/src/items/capacitor.cpp index c19b9cb06..f67376395 100644 --- a/src/items/capacitor.cpp +++ b/src/items/capacitor.cpp @@ -229,3 +229,16 @@ void Capacitor::getProperties(QHash & hash) { hash.insert(propertyDef->name, m_propertyDefs.value(propertyDef)); } } + +QHash Capacitor::prepareProps(ModelPart * modelPart, bool wantDebug, QStringList & keys) +{ + QHash props = ItemBase::prepareProps(modelPart, wantDebug, keys); + + // ensure capacitance and other properties are after family, if it is a capacitor; + if (keys.removeOne("capacitance")) { + keys.insert(1, "capacitance"); + if (keys.removeOne("voltage")) keys.insert(2, "voltage"); + } + + return props; +} diff --git a/src/items/capacitor.h b/src/items/capacitor.h index 5898b2353..b58e9e232 100644 --- a/src/items/capacitor.h +++ b/src/items/capacitor.h @@ -37,6 +37,7 @@ class Capacitor : public PaletteItem bool collectExtraInfo(QWidget * parent, const QString & family, const QString & prop, const QString & value, bool swappingEnabled, QString & returnProp, QString & returnValue, QWidget * & returnWidget, bool & hide); void setProp(const QString & prop, const QString & value); void getProperties(QHash &); + QHash prepareProps(ModelPart * modelPart, bool wantDebug, QStringList & keys); public slots: void textModified(QValidator::State state); diff --git a/src/items/itembase.cpp b/src/items/itembase.cpp index e8165cee1..bad4e15cf 100644 --- a/src/items/itembase.cpp +++ b/src/items/itembase.cpp @@ -1303,7 +1303,8 @@ FSvgRenderer * ItemBase::setUpImage(ModelPart * modelPart, LayerAttributes & lay //DebugDialog::debug(QString("set up image elapsed (1) %1").arg(t.elapsed()) ); - QString filename = PartFactory::getSvgFilename(modelPart, modelPartShared->imageFileName(layerAttributes.viewID, layerAttributes.viewLayerID), true, true); + QString imageFilename = modelPartShared->imageFileName(layerAttributes.viewID, layerAttributes.viewLayerID); + QString filename = PartFactory::getSvgFilename(modelPart, imageFilename, true, true); //#ifndef QT_NO_DEBUG //DebugDialog::debug(QString("set up image elapsed (2) %1").arg(t.elapsed()) ); @@ -1311,7 +1312,7 @@ FSvgRenderer * ItemBase::setUpImage(ModelPart * modelPart, LayerAttributes & lay if (filename.isEmpty()) { //QString deleteme = modelPartShared->domDocument()->toString(); - layerAttributes.error = tr("file for %1 %2 not found").arg(modelPartShared->title()).arg(modelPartShared->moduleID()); + layerAttributes.error = tr("file %1 for %2 not found").arg(imageFilename).arg(modelPartShared->moduleID()); return nullptr; } diff --git a/src/items/led.cpp b/src/items/led.cpp index 01d4eb478..320305121 100644 --- a/src/items/led.cpp +++ b/src/items/led.cpp @@ -62,7 +62,10 @@ QString LED::retrieveSvg(ViewLayer::ViewLayerID viewLayerID, QHashscene()) { + //Check if this an RGB led + QString rgbString = this->getProperty("rgb"); + if (this->scene() && rgbString.isEmpty()) { + //Set the color for the LED, does not apply if is is an RGB led setColor(prop("color")); } @@ -140,7 +143,7 @@ void LED::setColor(const QString & color) * @brief Restores the original brightness of an LED. */ void LED::resetBrightness() { - setBrightness(1-offColor); + setBrightness((1-offColor)/brigtnessMultiplier); if(m_ledLight && this->viewID()==ViewLayer::ViewID::BreadboardView) { m_ledLight->hide(); } @@ -155,7 +158,7 @@ void LED::resetBrightness() { * @brief Changes the brightness of an LED. * @param[in] brightness The brightness value, its range is from 0 (off) to 1 (on) */ -void LED::setBrightness(double brightness){ +void LED::setBrightness(double brightness) { QString errorStr; int errorLine; int errorColumn; @@ -166,14 +169,21 @@ void LED::setBrightness(double brightness){ //get the color of the LED QString colorString; - QString color = prop("color"); - foreach (PropertyDef * propertyDef, m_propertyDefs.keys()) { - if (propertyDef->name.compare("color") == 0) { - colorString = propertyDef->adjuncts.value(color, ""); - break; + QString rgbString = this->getProperty("rgb"); + if (rgbString.isEmpty()) { + //If it is just one LED, use color property + QString color = prop("color"); + foreach (PropertyDef * propertyDef, m_propertyDefs.keys()) { + if (propertyDef->name.compare("color") == 0) { + colorString = propertyDef->adjuncts.value(color, ""); + break; + } } + if (colorString.isEmpty()) return; + } else { + // It is an RGB led, set color to grey + colorString = "#E6E6E6"; } - if (colorString.isEmpty()) return; int red = colorString.mid(1,2).toInt(nullptr, 16); int green = colorString.mid(3,2).toInt(nullptr, 16); @@ -183,9 +193,12 @@ void LED::setBrightness(double brightness){ if (brightness < 0) brightness = 0; //Find the new color values - red = offColor*red + brightness*red; - green = offColor*green + brightness*green; - blue = offColor*blue + brightness*blue; + //The color achives maximum intensity when brightness = 1/brigtnessMultiplier + double brightnessColor = brightness * brigtnessMultiplier; + if (brightnessColor > 1) brightnessColor = 1; + red = offColor*red + brightnessColor*red; + green = offColor*green + brightnessColor*green; + blue = offColor*blue + brightnessColor*blue; if(red > 255) red = 255; if(green > 255) green = 255; if(blue > 255) blue = 255; @@ -210,6 +223,56 @@ void LED::setBrightness(double brightness){ } } +/** + * Changes the brightness of an RGB LED based on 3 brightness parameters. + * A brightness of 0 reduces scales the color to 30% of the color. + * + * @brief Changes the brightness of an RGB LED. + * @param[in] brightness The brightness values, its range is from 0 (off) to 1 (on) + */ +void LED::setBrightnessRGB(double brightnessR, double brightnessG, double brightnessB) { + QString errorStr; + int errorLine; + int errorColumn; + QDomDocument domDocument; + if (!domDocument.setContent( BreadboardSvg.value(m_filename), &errorStr, &errorLine, &errorColumn)) { + return; + } + + //The color achives maximum intensity when brightness = 0.25 + int red = 40 + (brightnessR * brigtnessMultiplier * 200.0); + int green = 40 + (brightnessG * brigtnessMultiplier * 200.0); + int blue = 40 + (brightnessB * brigtnessMultiplier * 200.0); + double brightness = std::max({brightnessR, brightnessG, brightnessB}); + + int maxColor = 230; //Do not saturate the colors + if (red > 255) red = maxColor; + if (red < 0) red = 0; + if (green > 255) green = maxColor; + if (green < 0) green = 0; + if (blue > 255) blue = maxColor; + if (blue < 0) blue = 0; + + QString newColorStr = QString("#%1%2%3") + .arg(red, 2, 16) + .arg(green, 2, 16) + .arg(blue, 2, 16); + newColorStr.replace(' ', '0'); + + //Change the color of the LED + QDomElement root = domDocument.documentElement(); + slamColor(root, newColorStr); + reloadRenderer(domDocument.toString(),true); + + //Add light comming out of the LED in BreadboardView + if(this->viewID()==ViewLayer::ViewID::BreadboardView) { + if(!m_ledLight) { + m_ledLight = new LedLight(this); + } + m_ledLight->setLight(brightness, red, green, blue); + } +} + QString LED::getColorSVG(const QString & color, ViewLayer::ViewLayerID viewLayerID) { QString errorStr; @@ -259,3 +322,14 @@ ViewLayer::ViewID LED::useViewIDForPixmap(ViewLayer::ViewID vid, bool swappingEn return ItemBase::useViewIDForPixmap(vid, swappingEnabled); } + +QHash LED::prepareProps(ModelPart * modelPart, bool wantDebug, QStringList & keys) +{ + QHash props = ItemBase::prepareProps(modelPart, wantDebug, keys); + + // ensure color and other properties are after family; + if (keys.removeOne("color")) keys.insert(1, "color"); + if (keys.removeOne("current")) keys.insert(2, "current"); + + return props; +} diff --git a/src/items/led.h b/src/items/led.h index 3753c039b..7559ceaea 100644 --- a/src/items/led.h +++ b/src/items/led.h @@ -37,21 +37,25 @@ class LedLight : public QGraphicsEllipseItem { ~LedLight() { }; void setLight(double brightness, int red, int green, int blue){ - if (brightness < 0.15) + //Only set light coming out if brightness is bigger than 0.25 + if (brightness < 0.25) brightness = 0.0; - double radious = std::min(parentItem()->boundingRect().width()/2, - parentItem()->boundingRect().height()/2) * brightness * 4; - prepareGeometryChange(); - setRect(-radious + parentItem()->boundingRect().width()/2, - -radious + parentItem()->boundingRect().width()/5, - radious*2, radious*2); - QRadialGradient gradient = QRadialGradient(0.5, 0.5, 0.5); - gradient.setCoordinateMode(QGradient::ObjectBoundingMode); - gradient.setColorAt(0, QColor(red, green, blue, 255)); - gradient.setColorAt(0.3, QColor(red, green, blue, 230)); - gradient.setColorAt(1, QColor(red, green, blue, 0)); - setBrush(gradient); - this->show(); + Capacitor* led = dynamic_cast(parentItem()); + if (led) { + double radious = std::min(led->boundingRectWithoutLegs().width()/2, + led->boundingRectWithoutLegs().height()/2) * brightness * 4; + prepareGeometryChange(); + setRect(-radious + led->boundingRectWithoutLegs().width()/2, + -radious + led->boundingRectWithoutLegs().width()/2, + radious*2, radious*2); + QRadialGradient gradient = QRadialGradient(0.5, 0.5, 0.5); + gradient.setCoordinateMode(QGradient::ObjectBoundingMode); + gradient.setColorAt(0, QColor(red, green, blue, 255)); + gradient.setColorAt(0.3, QColor(red, green, blue, 230)); + gradient.setColorAt(1, QColor(red, green, blue, 0)); + setBrush(gradient); + this->show(); + } }; }; @@ -62,6 +66,11 @@ class LED : public Capacitor //The color that remains when the brightness is set to 0 static constexpr double offColor = 0.3; + //The maximum color is achived when brigtness*brigtnessMultiplier=1 + //After that, more current increases the light comming out of the LED, + //but it does not change the color + static constexpr double brigtnessMultiplier = 4.0; + public: // after calling this constructor if you want to render the loaded svg (either from model or from file), MUST call LED(ModelPart *, ViewLayer::ViewID, const ViewGeometry & viewGeometry, long id, QMenu * itemMenu, bool doLabel); @@ -77,7 +86,9 @@ class LED : public Capacitor const QString & title(); ViewLayer::ViewID useViewIDForPixmap(ViewLayer::ViewID, bool swappingEnabled); void setBrightness(double); + void setBrightnessRGB(double brightnessR, double brightnessG, double brightnessB); void resetBrightness(); + QHash prepareProps(ModelPart * modelPart, bool wantDebug, QStringList & keys); protected: void setColor(const QString & color); diff --git a/src/items/moduleidnames.cpp b/src/items/moduleidnames.cpp index 2da7b6396..aac1a5e8b 100644 --- a/src/items/moduleidnames.cpp +++ b/src/items/moduleidnames.cpp @@ -44,6 +44,7 @@ const QString ModuleIDNames::PowerLabelModuleIDName = "PowerLabelModuleID"; const QString ModuleIDNames::LeftNetLabelModuleIDName = "LeftNetLabelModuleID"; const QString ModuleIDNames::JustPowerModuleIDName = "JustPowerModuleID"; const QString ModuleIDNames::ResistorModuleIDName = "ResistorModuleID"; +const QString ModuleIDNames::PhotocellModuleIDName = "PhotocellModuleID"; const QString ModuleIDNames::LogoTextModuleIDName = "LogoTextModuleID"; const QString ModuleIDNames::LogoImageModuleIDName = "LogoImageModuleID"; const QString ModuleIDNames::Silkscreen0LogoImageModuleIDName = "Silkscreen0LogoImageModuleID"; diff --git a/src/items/moduleidnames.h b/src/items/moduleidnames.h index 1a49a3cc6..679f83c9a 100644 --- a/src/items/moduleidnames.h +++ b/src/items/moduleidnames.h @@ -46,6 +46,7 @@ class ModuleIDNames static const QString LeftNetLabelModuleIDName; static const QString JustPowerModuleIDName; static const QString ResistorModuleIDName; + static const QString PhotocellModuleIDName; static const QString LogoTextModuleIDName; static const QString LogoImageModuleIDName; static const QString Silkscreen0LogoImageModuleIDName; diff --git a/src/items/resistor.cpp b/src/items/resistor.cpp index 69afc954f..a47a7d526 100644 --- a/src/items/resistor.cpp +++ b/src/items/resistor.cpp @@ -414,3 +414,18 @@ ViewLayer::ViewID Resistor::useViewIDForPixmap(ViewLayer::ViewID vid, bool swapp return ItemBase::useViewIDForPixmap(vid, swappingEnabled); } + +QHash Resistor::prepareProps(ModelPart * modelPart, bool wantDebug, QStringList & keys) +{ + QHash props = ItemBase::prepareProps(modelPart, wantDebug, keys); + + // ensure resistance and other properties are after family; + if (keys.removeOne("resistance")) + keys.insert(1, "resistance"); + if (keys.removeOne("tolerance")) + keys.insert(2, "tolerance"); + if (keys.removeOne("power")) + keys.insert(3, "power"); + + return props; +} diff --git a/src/items/resistor.h b/src/items/resistor.h index 6b3072f2a..c9b9e7190 100644 --- a/src/items/resistor.h +++ b/src/items/resistor.h @@ -50,6 +50,7 @@ class Resistor : public Capacitor void addedToScene(bool temporary); void setProp(const QString & prop, const QString & value); bool setUpImage(ModelPart* modelPart, const LayerHash & viewLayers, LayerAttributes &); + QHash prepareProps(ModelPart * modelPart, bool wantDebug, QStringList & keys); protected: QString makeSvg(const QString & ohms, ViewLayer::ViewLayerID viewLayerID); diff --git a/src/simulation/simulator.cpp b/src/simulation/simulator.cpp index b434b2dc1..d426dc30a 100644 --- a/src/simulation/simulator.cpp +++ b/src/simulation/simulator.cpp @@ -414,6 +414,44 @@ void Simulator::drawSmoke(ItemBase* part) { bbSmoke->setZValue(std::numeric_limits::max()); bbSmoke->setOpacity(0.7); schSmoke->setOpacity(0.7); + + //Scale the smoke images + QRectF bbPartBoundingBox = m_sch2bbItemHash.value(part)->boundingRectWithoutLegs(); + QRectF schSmokeBoundingBox = schSmoke->boundingRect(); + QRectF schPartBoundingBox = part->boundingRect(); + QRectF bbSmokeBoundingBox = bbSmoke->boundingRect(); + std::cout << "bbSmokeBoundingBox w and h: " << bbSmokeBoundingBox.width() << " " << bbSmokeBoundingBox.height() << std::endl; + + double scaleWidth = bbPartBoundingBox.width()/schSmokeBoundingBox.width(); + double scaleHeight = bbPartBoundingBox.height()/schSmokeBoundingBox.height(); + double scale; + (scaleWidth < scaleHeight) ? scale = scaleWidth : scale = scaleHeight; + if (scale > 1) { + //we can scale the smoke + bbSmoke->setScale(scale); + }else{ + scale = 1; //Do not scale down the smoke + } + + //Center the smoke in bb (bottom right corner of the smoke at the center of the part) + bbSmoke->setPos(QPointF(bbPartBoundingBox.width()/2-bbSmokeBoundingBox.width()*scale, + bbPartBoundingBox.height()/2-bbSmokeBoundingBox.height()*scale)); + + //Scale sch image + scaleWidth = schPartBoundingBox.width()/schSmokeBoundingBox.width(); + scaleHeight = schPartBoundingBox.height()/schSmokeBoundingBox.height(); + (scaleWidth < scaleHeight) ? scale = scaleWidth : scale = scaleHeight; + if (scale > 1) { + //we can scale the smoke + schSmoke->setScale(scale); + }else{ + scale = 1; //Do not scale down the smoke + } + + //Center the smoke in sch view (bottom right corner of the smoke at the center of the part) + schSmoke->setPos(QPointF(schPartBoundingBox.width()/2-schSmokeBoundingBox.width()*scale, + schPartBoundingBox.height()/2-schSmokeBoundingBox.height()*scale)); + part->addSimulationGraphicsItem(schSmoke); m_sch2bbItemHash.value(part)->addSimulationGraphicsItem(bbSmoke); } @@ -432,6 +470,7 @@ void Simulator::updateMultimeterScreen(ItemBase * multimeter, double number){ int indexPoint = textToDisplay.indexOf('.'); textToDisplay = TextUtils::convertToPowerPrefix(number, 'f', 4 - indexPoint); textToDisplay.replace('k', 'K'); + textToDisplay.replace("inf", "INF"); updateMultimeterScreen(multimeter, textToDisplay); } @@ -457,8 +496,10 @@ void Simulator::updateMultimeterScreen(ItemBase * multimeter, QString msg){ QGraphicsTextItem * schScreen = new QGraphicsTextItem(msg, multimeter); schScreen->setPos(QPointF(10,10)); schScreen->setZValue(std::numeric_limits::max()); + schScreen->setDefaultTextColor(QColor("black")); QFont font("Segment16C", 10, QFont::Normal); bbScreen->setFont(font); + bbScreen->setDefaultTextColor(QColor("black")); //There are issues as the size of the text changes depending on the display settings in windows //This hack scales the text to match the appropiate value QRectF bbMultBoundingBox = m_sch2bbItemHash.value(multimeter)->boundingRect(); @@ -470,7 +511,7 @@ void Simulator::updateMultimeterScreen(ItemBase * multimeter, QString msg){ bbScreen->setScale((0.8*bbMultBoundingBox.width())/bbBoundingBox.width()); schScreen->setScale((0.5*schMultBoundingBox.width())/schBoundingBox.width()); - //Update the boundiong box after scaling them + //Update the bounding box after scaling them bbBoundingBox = bbScreen->mapRectToParent(bbScreen->boundingRect()); schBoundingBox = schScreen->mapRectToParent(schScreen->boundingRect()); @@ -721,11 +762,17 @@ void Simulator::greyOutNonSimParts(const QSet& simParts) { QList noSimSchParts = m_schematicGraphicsView->scene()->items(); QList noSimBbParts = m_breadboardGraphicsView->scene()->items(); - //Remove the parts that are going to be simulated and the wires connected to them QList bbConnectors; foreach (ItemBase * part, simParts) { - noSimSchParts.removeAll(part); + foreach (QGraphicsItem * schItem, noSimSchParts) { + ItemBase * schPart = dynamic_cast(schItem); + if (!schPart) continue; + if (part->instanceTitle().compare(schPart->instanceTitle()) == 0) { + noSimSchParts.removeAll(schItem); + } + } + noSimBbParts.removeAll(m_sch2bbItemHash.value(part)); bbConnectors.append(m_sch2bbItemHash.value(part)->cachedConnectorItems()); @@ -765,12 +812,49 @@ void Simulator::greyOutParts(const QList & parts) { QGraphicsColorizeEffect * schEffect = new QGraphicsColorizeEffect(); schEffect->setColor(QColor(100,100,100)); part->setGraphicsEffect(schEffect); + + //Add a reason for not simulate them + ItemBase* item = dynamic_cast(part); + if (item) { + QString msg = "NOT SIMULATED:"; + if (item->spice().isEmpty()) { + //There is no SPICE model + msg += "\nNO SPICE"; + } else { + msg += "\nNOT CONNECTED"; + } + QGraphicsTextItem * infoText = new QGraphicsTextItem(msg, part); + infoText->setZValue(std::numeric_limits::max()); + infoText->setDefaultTextColor(QColor("black")); + QFont font("OCRA", 4, QFont::Normal); + infoText->setFont(font); + + //There are issues as the size of the text changes depending on the display settings in windows + //This hack scales the text to match the appropiate value + QRectF partBoundingBox = item->boundingRectWithoutLegs(); + QRectF infoTextBoundingBox = infoText->boundingRect(); + + if (infoTextBoundingBox.width() > partBoundingBox.width()) { + //Scale down the text to 90% percent of the partsĀ“s width + double scale = partBoundingBox.width()/infoTextBoundingBox.width()*0.9; + infoText->setScale(scale); + } + + //Update the bounding box after scaling them + infoTextBoundingBox = infoText->mapRectToParent(infoText->boundingRect()); + + //Set text on top of part + infoText->setPos(QPointF(0,-infoTextBoundingBox.height())); + + item->addSimulationGraphicsItem(infoText); + } } } /** * Removes items that are being simulated but without spice lines. Basically, remove - * the wires and the breadboards, which are part of the simulation and leave the rest. + * the wires, breadboards, power symbols, etc. (which are part of the simulation) and + * leave the rest. * @param[in/out] parts A list of parts which will be filtered to remove parts that * are being simulated */ @@ -844,6 +928,19 @@ void Simulator::removeItemsToBeSimulated(QList & parts) { parts.removeAll(part); continue; } + + ItemBase* item = dynamic_cast(part); + if (!item) { + //We only remove the parts, we do not touch other elements of the scene (text of the net labels, etc.) + parts.removeAll(part); + } else { + if (item->family().compare("power label") == 0 + || item->family().compare("net label") == 0 + || item->family().compare("breadboard") == 0) //hack as half+ is not generated as breadboard object, see #3873 + { + parts.removeAll(part); + } + } } } @@ -871,17 +968,40 @@ void Simulator::updateDiode(ItemBase * diode) { void Simulator::updateLED(ItemBase * part) { LED* led = dynamic_cast(part); if (led) { - double curr = getCurrent(part); - double maxCurr = getMaxPropValue(part, "current"); - - std::cout << "LED Current: " <(m_sch2bbItemHash.value(part)); - bbLed->setBrightness(curr/maxCurr); - if (curr > maxCurr) { - drawSmoke(part); - bbLed->setBrightness(0); + //Check if this an RGB led + QString rgbString = part->getProperty("rgb"); + + if (rgbString.isEmpty()) { + // Just one LED + double curr = getCurrent(part); + double maxCurr = getMaxPropValue(part, "current"); + + std::cout << "LED Current: " <(m_sch2bbItemHash.value(part)); + bbLed->setBrightness(curr/maxCurr); + if (curr > maxCurr) { + drawSmoke(part); + bbLed->setBrightness(0); + } + } else { + // The part is an RGB LED + double currR = getCurrent(part, "R"); + double currG = getCurrent(part, "G"); + double currB = getCurrent(part, "B"); + double curr = std::max({currR, currG, currB}); + double maxCurr = getMaxPropValue(part, "current"); + + std::cout << "LED Current (R, G, B): " << currR << " " << currG << " " << currB <(m_sch2bbItemHash.value(part)); + bbLed->setBrightnessRGB(currR/maxCurr, currG/maxCurr, currB/maxCurr); + if (curr > maxCurr) { + drawSmoke(part); + bbLed->setBrightness(0); + } } } else { //It is probably an LED display (LED matrix) @@ -918,7 +1038,7 @@ void Simulator::updateCapacitor(ItemBase * part) { } } else { //This is an electrolytic o tantalum capacitor (polarized) - if (v > maxV/2 || v < 0) { + if (v > maxV/2 || v < HarmfulNegativeVoltage) { drawSmoke(part); } } @@ -1011,7 +1131,8 @@ void Simulator::updateIRSensor(ItemBase * part) { i = getCurrent(part, "a"); //voltage applied to the motor } std::cout << "IR sensor Max Iout: " << maxIout << ", current Iout " << i << std::endl; - if (v > maxV || v < 0 || abs(i) > maxIout) { + std::cout << "IR sensor Max V: " << maxV << ", current V " << v << std::endl; + if (v > maxV || v < HarmfulNegativeVoltage || abs(i) > maxIout) { drawSmoke(part); return; } @@ -1055,6 +1176,32 @@ void Simulator::updateDcMotor(ItemBase * part) { schRotate = new QGraphicsSvgItem(image, part); if (!bbRotate || !schRotate) return; + //Scale the smoke images + QRectF bbPartBoundingBox = m_sch2bbItemHash.value(part)->boundingRectWithoutLegs(); + QRectF schRotateBoundingBox = schRotate->boundingRect(); + QRectF schPartBoundingBox = part->boundingRect(); + QRectF bbRotateBoundingBox = bbRotate->boundingRect(); + + + double scaleWidth = bbPartBoundingBox.width()/bbRotateBoundingBox.width(); + double scaleHeight = bbPartBoundingBox.height()/bbRotateBoundingBox.height(); + double scale; + scale = std::max(scaleWidth, scaleHeight)*0.5; + bbRotate->setScale(scale); + + //Center the arrow in bb + bbRotate->setPos(QPointF(bbPartBoundingBox.width()/2-bbRotateBoundingBox.width()*scale/2, + bbPartBoundingBox.height()/2-bbRotateBoundingBox.height()*scale/2)); + + scaleWidth = schPartBoundingBox.width()/schRotateBoundingBox.width(); + scaleHeight = schPartBoundingBox.height()/schRotateBoundingBox.height(); + scale = std::max(scaleWidth, scaleHeight)*0.5; + schRotate->setScale(scale); + + //Center the arrow in bb + schRotate->setPos(QPointF(schPartBoundingBox.width()/2-schRotateBoundingBox.width()*scale/2, + schPartBoundingBox.height()/2-schRotateBoundingBox.height()*scale/2)); + schRotate->setZValue(std::numeric_limits::max()); bbRotate->setZValue(std::numeric_limits::max()); part->addSimulationGraphicsItem(schRotate); diff --git a/src/simulation/simulator.h b/src/simulation/simulator.h index 52d6ece5c..359750682 100644 --- a/src/simulation/simulator.h +++ b/src/simulation/simulator.h @@ -94,7 +94,8 @@ public slots: QList* m_instanceTitleSim; QTimer *m_simTimer; - static constexpr int SimDelay = 200; + static constexpr int SimDelay = 400; + static constexpr double HarmfulNegativeVoltage = -0.5; }; diff --git a/src/utils/boundedregexpvalidator.h b/src/utils/boundedregexpvalidator.h index 1bd27924e..1360f44e2 100644 --- a/src/utils/boundedregexpvalidator.h +++ b/src/utils/boundedregexpvalidator.h @@ -61,9 +61,10 @@ class BoundedRegExpValidator : public QRegExpValidator QValidator::State validate ( QString & input, int & pos ) const override { QValidator::State state = QRegExpValidator::validate(input, pos); input.replace(m_symbol, ""); + + state = QRegExpValidator::validate(input, pos); if(!m_symbol.isEmpty()) input.append(m_symbol); - state = QRegExpValidator::validate(input, pos); if ( state == QValidator::Acceptable ) { double converted = m_converter(input, m_symbol);