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);