summaryrefslogtreecommitdiffstats
path: root/src/electronics/components
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-02-24 01:49:02 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-02-24 01:49:02 +0000
commit5de3dd4762ca33a0f92e79ffa4fe2ff67069d531 (patch)
treebad482b7afa4cdf47422d60a5dd2c61c7e333b09 /src/electronics/components
downloadktechlab-5de3dd4762ca33a0f92e79ffa4fe2ff67069d531.tar.gz
ktechlab-5de3dd4762ca33a0f92e79ffa4fe2ff67069d531.zip
Added KDE3 version of ktechlab
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/ktechlab@1095338 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'src/electronics/components')
-rw-r--r--src/electronics/components/Makefile.am33
-rw-r--r--src/electronics/components/addac.cpp281
-rw-r--r--src/electronics/components/addac.h93
-rw-r--r--src/electronics/components/bidirled.cpp157
-rw-r--r--src/electronics/components/bidirled.h45
-rw-r--r--src/electronics/components/binarycounter.cpp186
-rw-r--r--src/electronics/components/binarycounter.h63
-rw-r--r--src/electronics/components/bussplitter.cpp133
-rw-r--r--src/electronics/components/bussplitter.h45
-rw-r--r--src/electronics/components/demultiplexer.cpp175
-rw-r--r--src/electronics/components/demultiplexer.h46
-rw-r--r--src/electronics/components/dependentsource.cpp314
-rw-r--r--src/electronics/components/dependentsource.h112
-rw-r--r--src/electronics/components/discretelogic.cpp308
-rw-r--r--src/electronics/components/discretelogic.h110
-rw-r--r--src/electronics/components/ec555.cpp172
-rw-r--r--src/electronics/components/ec555.h56
-rw-r--r--src/electronics/components/ecbcdto7segment.cpp158
-rw-r--r--src/electronics/components/ecbcdto7segment.h41
-rw-r--r--src/electronics/components/ecbjt.cpp153
-rw-r--r--src/electronics/components/ecbjt.h42
-rw-r--r--src/electronics/components/eccapacitor.cpp92
-rw-r--r--src/electronics/components/eccapacitor.h40
-rw-r--r--src/electronics/components/ecclockinput.cpp185
-rw-r--r--src/electronics/components/ecclockinput.h56
-rw-r--r--src/electronics/components/eccurrentsignal.cpp92
-rw-r--r--src/electronics/components/eccurrentsignal.h36
-rw-r--r--src/electronics/components/eccurrentsource.cpp94
-rw-r--r--src/electronics/components/eccurrentsource.h36
-rw-r--r--src/electronics/components/ecdiode.cpp120
-rw-r--r--src/electronics/components/ecdiode.h35
-rw-r--r--src/electronics/components/ecfixedvoltage.cpp77
-rw-r--r--src/electronics/components/ecfixedvoltage.h35
-rw-r--r--src/electronics/components/ecground.cpp66
-rw-r--r--src/electronics/components/ecground.h33
-rw-r--r--src/electronics/components/eckeypad.cpp199
-rw-r--r--src/electronics/components/eckeypad.h42
-rw-r--r--src/electronics/components/ecled.cpp134
-rw-r--r--src/electronics/components/ecled.h48
-rw-r--r--src/electronics/components/ecopamp.cpp85
-rw-r--r--src/electronics/components/ecopamp.h35
-rw-r--r--src/electronics/components/ecpotentiometer.cpp119
-rw-r--r--src/electronics/components/ecpotentiometer.h43
-rw-r--r--src/electronics/components/ecresistor.cpp76
-rw-r--r--src/electronics/components/ecresistor.h36
-rw-r--r--src/electronics/components/ecsevensegment.cpp210
-rw-r--r--src/electronics/components/ecsevensegment.h50
-rw-r--r--src/electronics/components/ecsignallamp.cpp86
-rw-r--r--src/electronics/components/ecsignallamp.h40
-rw-r--r--src/electronics/components/ecsubcircuit.cpp130
-rw-r--r--src/electronics/components/ecsubcircuit.h61
-rw-r--r--src/electronics/components/ecvoltagesignal.cpp95
-rw-r--r--src/electronics/components/ecvoltagesignal.h36
-rw-r--r--src/electronics/components/ecvoltagesource.cpp93
-rw-r--r--src/electronics/components/ecvoltagesource.h37
-rw-r--r--src/electronics/components/externalconnection.cpp78
-rw-r--r--src/electronics/components/externalconnection.h35
-rw-r--r--src/electronics/components/flipflop.cpp347
-rw-r--r--src/electronics/components/flipflop.h107
-rw-r--r--src/electronics/components/fulladder.cpp91
-rw-r--r--src/electronics/components/fulladder.h37
-rw-r--r--src/electronics/components/inductor.cpp84
-rw-r--r--src/electronics/components/inductor.h35
-rw-r--r--src/electronics/components/magnitudecomparator.cpp206
-rw-r--r--src/electronics/components/magnitudecomparator.h50
-rw-r--r--src/electronics/components/matrixdisplay.cpp291
-rw-r--r--src/electronics/components/matrixdisplay.h60
-rw-r--r--src/electronics/components/matrixdisplaydriver.cpp380
-rw-r--r--src/electronics/components/matrixdisplaydriver.h42
-rw-r--r--src/electronics/components/meter.cpp265
-rw-r--r--src/electronics/components/meter.h103
-rw-r--r--src/electronics/components/multiinputgate.cpp530
-rw-r--r--src/electronics/components/multiinputgate.h160
-rw-r--r--src/electronics/components/multiplexer.cpp176
-rw-r--r--src/electronics/components/multiplexer.h46
-rw-r--r--src/electronics/components/parallelportcomponent.cpp241
-rw-r--r--src/electronics/components/parallelportcomponent.h49
-rw-r--r--src/electronics/components/piccomponent.cpp437
-rw-r--r--src/electronics/components/piccomponent.h97
-rw-r--r--src/electronics/components/piccomponentpin.cpp172
-rw-r--r--src/electronics/components/piccomponentpin.h68
-rw-r--r--src/electronics/components/probe.cpp291
-rw-r--r--src/electronics/components/probe.h113
-rw-r--r--src/electronics/components/pushswitch.cpp204
-rw-r--r--src/electronics/components/pushswitch.h62
-rw-r--r--src/electronics/components/ram.cpp232
-rw-r--r--src/electronics/components/ram.h51
-rw-r--r--src/electronics/components/resistordip.cpp132
-rw-r--r--src/electronics/components/resistordip.h43
-rw-r--r--src/electronics/components/rotoswitch.cpp317
-rw-r--r--src/electronics/components/rotoswitch.h70
-rw-r--r--src/electronics/components/serialportcomponent.cpp242
-rw-r--r--src/electronics/components/serialportcomponent.h61
-rw-r--r--src/electronics/components/toggleswitch.cpp407
-rw-r--r--src/electronics/components/toggleswitch.h116
95 files changed, 11903 insertions, 0 deletions
diff --git a/src/electronics/components/Makefile.am b/src/electronics/components/Makefile.am
new file mode 100644
index 0000000..c388cf6
--- /dev/null
+++ b/src/electronics/components/Makefile.am
@@ -0,0 +1,33 @@
+INCLUDES = -I$(top_srcdir)/src \
+ -I$(top_srcdir)/src/electronics -I$(top_srcdir)/src/electronics/components \
+ -I$(top_srcdir)/src/electronics/simulation -I$(top_srcdir)/src/gui -I$(top_srcdir)/src/languages \
+ -I$(top_srcdir)/src/micro $(glib_cflags) $(all_includes)
+
+METASOURCES = AUTO
+noinst_HEADERS = ecresistor.h ecled.h ecdiode.h ecsevensegment.h eckeypad.h \
+ eccapacitor.h ec555.h eccurrentsource.h ecfixedvoltage.h ecbcdto7segment.h \
+ ecsignallamp.h ecclockinput.h ecpotentiometer.h ecopamp.h ecvoltagesource.h \
+ eccurrentsignal.h ecvoltagesignal.h ecground.h multiinputgate.h fulladder.h multiplexer.h \
+ demultiplexer.h externalconnection.h ecsubcircuit.h meter.h probe.h resistordip.h \
+ addac.h dependentsource.h flipflop.h toggleswitch.h pushswitch.h ram.h \
+ discretelogic.h piccomponent.h piccomponentpin.h binarycounter.h bidirled.h \
+ matrixdisplay.h bussplitter.h matrixdisplaydriver.h magnitudecomparator.h \
+ serialportcomponent.h parallelportcomponent.h inductor.h ecbjt.h rotoswitch.h
+
+noinst_LTLIBRARIES = libcomponents.la
+libcomponents_la_SOURCES = ecresistor.cpp ecled.cpp ecdiode.cpp \
+ ecsevensegment.cpp eckeypad.cpp eccapacitor.cpp ec555.cpp eccurrentsource.cpp \
+ ecfixedvoltage.cpp ecbcdto7segment.cpp ecsignallamp.cpp ecclockinput.cpp \
+ ecpotentiometer.cpp ecopamp.cpp ecvoltagesource.cpp eccurrentsignal.cpp ecvoltagesignal.cpp \
+ ecground.cpp multiinputgate.cpp fulladder.cpp multiplexer.cpp demultiplexer.cpp \
+ externalconnection.cpp ecsubcircuit.cpp meter.cpp probe.cpp resistordip.cpp addac.cpp \
+ dependentsource.cpp flipflop.cpp toggleswitch.cpp pushswitch.cpp ram.cpp discretelogic.cpp \
+ piccomponent.cpp piccomponentpin.cpp binarycounter.cpp bidirled.cpp matrixdisplay.cpp \
+ bussplitter.cpp matrixdisplaydriver.cpp magnitudecomparator.cpp serialportcomponent.cpp \
+ parallelportcomponent.cpp inductor.cpp ecbjt.cpp rotoswitch.cpp
+
+libcomponents_la_PCH = AUTO
+
+
+libcomponents_la_LIBADD =\
+ $(top_builddir)/src/electronics/simulation/libelements.la
diff --git a/src/electronics/components/addac.cpp b/src/electronics/components/addac.cpp
new file mode 100644
index 0000000..a58e2d8
--- /dev/null
+++ b/src/electronics/components/addac.cpp
@@ -0,0 +1,281 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "addac.h"
+#include "ecnode.h"
+#include "logic.h"
+#include "libraryitem.h"
+#include "pin.h"
+#include "voltagepoint.h"
+
+#include <cmath>
+#include <kiconloader.h>
+#include <klocale.h>
+
+
+Item* ADC::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ADC( (ICNDocument*)itemDocument, newItem, id );
+}
+
+
+Item* DAC::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new DAC( (ICNDocument*)itemDocument, newItem, id );
+}
+
+
+LibraryItem* ADC::libraryItem()
+{
+ return new LibraryItem(
+ "ec/adc",
+ i18n("Analog-Digital"),
+ i18n("Integrated Circuits"),
+ "ic1.png",
+ LibraryItem::lit_component,
+ ADC::construct
+ );
+}
+
+
+LibraryItem* DAC::libraryItem()
+{
+ return new LibraryItem(
+ "ec/dac",
+ i18n("Digital-Analog"),
+ i18n("Integrated Circuits"),
+ "ic1.png",
+ LibraryItem::lit_component,
+ DAC::construct
+ );
+}
+
+
+//BEGIN class ADDAC
+ADDAC::ADDAC( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, id )
+{
+ m_numBits = 0;
+ m_range = 0;
+
+ createProperty( "numBits", Variant::Type::Int );
+ property("numBits")->setCaption( i18n("Number Bits") );
+ property("numBits")->setMinValue(2);
+ property("numBits")->setMaxValue(max_ADDAC_bits);
+ property("numBits")->setValue(2);
+
+ createProperty( "range", Variant::Type::Double );
+ property("range")->setCaption( i18n("Input Range") );
+ property("range")->setUnit("V");
+ property("range")->setMinValue(-1e12);
+ property("range")->setMaxValue(1e12);
+ property("range")->setValue(5);
+}
+
+ADDAC::~ADDAC()
+{
+}
+
+
+void ADDAC::dataChanged()
+{
+ m_range = dataDouble("range");
+ initPins();
+}
+
+//END class ADDAC
+
+
+
+
+//BEGIN class ADC
+ADC::ADC( ICNDocument *icnDocument, bool newItem, const char *id )
+ : ADDAC( icnDocument, newItem, (id) ? id : "adc" )
+{
+ m_name = i18n("ADC");
+ m_desc = i18n("Converts an analog signal into a digital output.");
+
+ for ( int i=0; i<max_ADDAC_bits; ++i )
+ m_logic[i] = 0l;
+
+ m_realNode = 0l;
+}
+
+ADC::~ADC()
+{
+}
+
+
+void ADC::stepNonLogic()
+{
+ double floatBitValue = m_realNode->pin()->voltage() * (std::pow( 2, double(m_numBits) )-1.) / m_range;
+ double roundBitValue = std::floor( floatBitValue+0.5 );
+
+ if ( roundBitValue < 0 )
+ {
+ for ( int i = 0; i<m_numBits; ++i )
+ m_logic[i]->setHigh(false);
+ return;
+ }
+
+ uint roundedBitValue = uint(roundBitValue);
+ for ( int i = 0; i<m_numBits; ++i )
+ m_logic[i]->setHigh( roundedBitValue & ( 1 << i ) );
+}
+
+
+void ADC::initPins()
+{
+ int numBits = dataInt("numBits");
+
+ if ( numBits < 2 )
+ numBits = 2;
+ else if ( numBits > max_ADDAC_bits )
+ numBits = max_ADDAC_bits;
+
+ if ( numBits == m_numBits )
+ return;
+
+ QStringList pins;
+
+ int inPos = (numBits-1+(numBits%2))/2;
+ for ( int i=0; i<inPos; ++i )
+ pins += "";
+
+ pins += "In";
+
+ for ( int i=inPos+1; i<numBits; ++i )
+ pins += "";
+
+ for ( int i=numBits-1; i>=0; --i )
+ pins += QString::number(i);
+
+ initDIPSymbol( pins, 64 );
+ initDIP(pins);
+
+ if (!m_realNode)
+ m_realNode = ecNodeWithID("In");
+
+
+ if ( numBits > m_numBits )
+ {
+ for ( int i=m_numBits; i<numBits; ++i )
+ {
+ ECNode *node = ecNodeWithID( QString::number(i) );
+ m_logic[i] = createLogicOut( node, false );
+ }
+ }
+ else
+ {
+ for ( int i=numBits; i<m_numBits; ++i )
+ {
+ QString id = QString::number(i);
+ removeDisplayText(id);
+ removeElement( m_logic[i], false );
+ removeNode(id);
+ m_logic[i] = 0l;
+ }
+ }
+
+ m_numBits = numBits;
+}
+//END class ADC
+
+
+
+
+//BEGIN class DAC
+DAC::DAC( ICNDocument *icnDocument, bool newItem, const char *id )
+ : ADDAC( icnDocument, newItem, (id) ? id : "dac" )
+{
+ m_name = i18n("DAC");
+ m_desc = i18n("Converts a digital input to an analog output signal.");
+
+ for ( int i=0; i<max_ADDAC_bits; ++i )
+ m_logic[i] = 0l;
+
+ m_voltagePoint = 0l;
+}
+
+
+DAC::~DAC()
+{
+}
+
+
+void DAC::stepNonLogic()
+{
+ uint value = 0;
+ for ( int i=0; i<m_numBits; ++i )
+ value |= ( m_logic[i]->isHigh() ? 1 : 0 ) << i;
+
+// double valueAsDouble = double(value);
+// double powChange = std::pow( double(m_numBits), 2 )-1.;
+// m_voltagePoint->setVoltage( m_range * valueAsDouble / powChange );
+ m_voltagePoint->setVoltage( m_range * double(value) / (std::pow( 2, double(m_numBits) )-1.) );
+}
+
+
+void DAC::initPins()
+{
+ int numBits = dataInt("numBits");
+
+ if ( numBits < 2 )
+ numBits = 2;
+ else if ( numBits > max_ADDAC_bits )
+ numBits = max_ADDAC_bits;
+
+ if ( numBits == m_numBits )
+ return;
+
+ QStringList pins;
+
+ for ( int i=0; i<numBits; ++i )
+ pins += QString::number(i);
+
+ int inPos = (numBits+1+(numBits%2))/2;
+ for ( int i=numBits-1; i>=inPos; --i )
+ pins += "";
+
+ pins += "Out";
+
+ for ( int i=inPos-2; i>=0; --i )
+ pins += "";
+
+ initDIPSymbol( pins, 64 );
+ initDIP(pins);
+
+ if (!m_voltagePoint)
+ m_voltagePoint = createVoltagePoint( ecNodeWithID("Out"), 0. );
+
+ if ( numBits > m_numBits )
+ {
+ for ( int i=m_numBits; i<numBits; ++i )
+ {
+ ECNode *node = ecNodeWithID( QString::number(i) );
+ m_logic[i] = createLogicIn(node);
+ }
+ }
+ else
+ {
+ for ( int i=numBits; i<m_numBits; ++i )
+ {
+ QString id = QString::number(i);
+ removeDisplayText(id);
+ removeElement( m_logic[i], false );
+ removeNode(id);
+ m_logic[i] = 0l;
+ }
+ }
+
+ m_numBits = numBits;
+}
+//END class DAC
+
diff --git a/src/electronics/components/addac.h b/src/electronics/components/addac.h
new file mode 100644
index 0000000..3d69e88
--- /dev/null
+++ b/src/electronics/components/addac.h
@@ -0,0 +1,93 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef ADDAC_H
+#define ADDAC_H
+
+#include "component.h"
+
+const int max_ADDAC_bits = 32;
+
+/**
+@author David Saxton
+*/
+class ADDAC : public Component
+{
+public:
+ public:
+ ADDAC( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ADDAC();
+ virtual bool canFlip() const { return true; }
+
+ protected:
+ void dataChanged();
+ /**
+ * Add / remove pins according to the number of outputs the user has requested
+ */
+ virtual void initPins() = 0;
+
+ int m_numBits;
+ double m_range;
+};
+
+
+/**
+@author David Saxton
+ */
+class ADC : public ADDAC
+{
+ public:
+ ADC( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ADC();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+ virtual void stepNonLogic();
+ virtual bool doesStepNonLogic() const { return true; }
+
+ protected:
+ /**
+ * Add / remove pins according to the number of outputs the user has requested
+ */
+ virtual void initPins();
+
+ LogicOut *m_logic[max_ADDAC_bits];
+ ECNode *m_realNode;
+};
+
+
+/**
+@author David Saxton
+ */
+class DAC : public ADDAC
+{
+ public:
+ DAC( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~DAC();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+ virtual void stepNonLogic();
+ virtual bool doesStepNonLogic() const { return true; }
+
+ protected:
+ /**
+ * Add / remove pins according to the number of outputs the user has requested
+ */
+ virtual void initPins();
+
+ LogicIn *m_logic[max_ADDAC_bits];
+ VoltagePoint *m_voltagePoint;
+};
+
+
+#endif
diff --git a/src/electronics/components/bidirled.cpp b/src/electronics/components/bidirled.cpp
new file mode 100644
index 0000000..92e242d
--- /dev/null
+++ b/src/electronics/components/bidirled.cpp
@@ -0,0 +1,157 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "bidirled.h"
+#include "colorcombo.h"
+#include "diode.h"
+#include "ecled.h"
+#include "ecnode.h"
+#include "libraryitem.h"
+#include "simulator.h"
+
+#include <klocale.h>
+#include <qpainter.h>
+
+Item* BiDirLED::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new BiDirLED( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* BiDirLED::libraryItem()
+{
+ return new LibraryItem (
+ "ec/bidir_led",
+ i18n("Bidirectional LED"),
+ i18n("Outputs"),
+ "bidirled.png",
+ LibraryItem::lit_component,
+ BiDirLED::construct
+ );
+}
+
+BiDirLED::BiDirLED( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, id ? id : "bidir_led" )
+{
+ m_name = i18n("Bidirectional LED");
+ m_desc = i18n("Bidrectional Light Emitting Diode");
+ m_bDynamicContent = true;
+
+ setSize( -8, -16, 16, 32 );
+ init1PinLeft();
+ init1PinRight();
+ setSize( -8, -24, 24, 40 );
+
+ m_pDiode[0] = createDiode( m_pNNode[0], m_pPNode[0] );
+ m_pDiode[1] = createDiode( m_pPNode[0], m_pNNode[0] );
+
+ avg_brightness[0] = avg_brightness[1] = 255;
+ lastUpdatePeriod = 0.;
+ r[0]=r[1]=g[0]=g[1]=b[0]=b[1]=0;
+ last_brightness[0] = last_brightness[1] = 255;
+
+ createProperty( "0-color1", Variant::Type::Color );
+ property("0-color1")->setCaption( i18n("Color 1") );
+ property("0-color1")->setColorScheme( ColorCombo::LED );
+
+ createProperty( "0-color2", Variant::Type::Color );
+ property("0-color2")->setCaption( i18n("Colour 2") );
+ property("0-color2")->setColorScheme( ColorCombo::LED );
+}
+
+BiDirLED::~BiDirLED()
+{
+}
+
+void BiDirLED::dataChanged()
+{
+ QString colors[] = { "0-color1", "0-color2" };
+ for ( unsigned i = 0; i < 2; i++ )
+ {
+ QColor color = dataColor(colors[i]);
+ r[i] = color.red();
+ g[i] = color.green();
+ b[i] = color.blue();
+ r[i] /= 0x100;
+ g[i] /= 0x100;
+ b[i] /= 0x100;
+ }
+}
+
+void BiDirLED::stepNonLogic()
+{
+ double interval = 1./LINEAR_UPDATE_RATE;
+ lastUpdatePeriod += interval;
+
+ for ( unsigned i = 0; i < 2; i++ )
+ avg_brightness[i] += ECLed::brightness(m_pDiode[i]->current())*interval;
+}
+
+void BiDirLED::drawShape( QPainter &p )
+{
+ initPainter(p);
+
+ for ( unsigned i = 0; i < 2; i++ )
+ {
+ uint _b;
+ if ( lastUpdatePeriod == 0. )
+ _b = last_brightness[i];
+
+ else
+ {
+ _b = uint(avg_brightness[i]/lastUpdatePeriod);
+ last_brightness[i] = _b;
+ }
+ avg_brightness[i] = 0.;
+
+ p.setBrush( QColor( uint(255-(255-_b)*(1-r[i])), uint(255-(255-_b)*(1-g[i])), uint(255-(255-_b)*(1-b[i])) ) );
+
+
+ QPointArray pa(3);
+ if ( i == 0 )
+ {
+ pa[0] = QPoint( 8, -8 );
+ pa[1] = QPoint( -8, -16 );
+ pa[2] = QPoint( -8, 0 );
+ }
+ else
+ {
+ pa[0] = QPoint( -8, 8 );
+ pa[1] = QPoint( 8, 0 );
+ pa[2] = QPoint( 8, 16 );
+ }
+
+ pa.translate( int(x()), int(y()) );
+ p.drawPolygon(pa);
+ p.drawPolyline(pa);
+ }
+ lastUpdatePeriod = 0.;
+
+ // Draw the arrows indicating it's a LED
+ int _x = (int)x()-2;
+ int _y = (int)y()-21;
+
+ p.drawLine( _x+9, _y+3, _x+12, _y ); // Tail of left arrow
+ p.drawLine( _x+12, _y, _x+10, _y ); // Left edge of left arrow tip
+ p.drawLine( _x+12, _y, _x+12, _y+2 ); // Right edge of left arrow tip
+
+ p.drawLine( _x+12, _y+6, _x+15, _y+3 ); // Tail of right arrow
+ p.drawLine( _x+15, _y+3, _x+13, _y+3 ); // Left edge of right arrow tip
+ p.drawLine( _x+15, _y+3, _x+15, _y+5 ); // Right edge of right arrow tip
+
+ p.drawLine( _x+10, _y, _x+15, _y+5 ); // Diagonal line that forms base of both arrow tips
+
+ _x = int(x());
+ _y = int(y());
+ p.drawLine( _x+8, _y-16, _x+8, _y );
+ p.drawLine( _x-8, _y, _x-8, _y+16 );
+
+ deinitPainter(p);
+}
+
diff --git a/src/electronics/components/bidirled.h b/src/electronics/components/bidirled.h
new file mode 100644
index 0000000..e80f4e0
--- /dev/null
+++ b/src/electronics/components/bidirled.h
@@ -0,0 +1,45 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef BIDIRLED_H
+#define BIDIRLED_H
+
+#include <component.h>
+
+/**
+@author David Saxton
+*/
+class BiDirLED : public Component
+{
+ public:
+ BiDirLED( ICNDocument * icnDocument, bool newItem, const char *id = 0L );
+ ~BiDirLED();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+ virtual void dataChanged();
+ virtual void stepNonLogic();
+ virtual bool doesStepNonLogic() const { return true; }
+
+ private:
+ virtual void drawShape( QPainter &p );
+
+ double r[2];
+ double g[2];
+ double b[2];
+
+ double avg_brightness[2];
+ uint last_brightness[2];
+ double lastUpdatePeriod;
+ Diode *m_pDiode[2];
+};
+
+#endif
diff --git a/src/electronics/components/binarycounter.cpp b/src/electronics/components/binarycounter.cpp
new file mode 100644
index 0000000..f278104
--- /dev/null
+++ b/src/electronics/components/binarycounter.cpp
@@ -0,0 +1,186 @@
+/***************************************************************************
+ * Copyright (C) 2003-2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "binarycounter.h"
+
+#include "logic.h"
+#include "libraryitem.h"
+
+#include <kiconloader.h>
+#include <klocale.h>
+
+Item* BinaryCounter::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new BinaryCounter( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* BinaryCounter::libraryItem()
+{
+ QStringList ids;
+ ids << "ec/binary_counter" << "ec/4_bit_binary_counter";
+ return new LibraryItem(
+ ids,
+ i18n("Binary Counter"),
+ i18n("Integrated Circuits"),
+ "ic1.png",
+ LibraryItem::lit_component,
+ BinaryCounter::construct
+ );
+}
+
+BinaryCounter::BinaryCounter( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, id ? id : "binary_counter" )
+{
+ m_name = i18n("Binary Counter");
+ m_desc = i18n("Holds an internal count, which changes when the clock input <i>&gt;</i> pin is pulsed.<br><br>"
+ "Normal operation: <i>en</i> (Enable) and <i>u/d</i> (Up/Down) are held high, <i>r</i> (Reset) is low.");
+
+ enLogic = inLogic = rLogic = udLogic = 0L;
+
+ b_reset = false;
+ b_triggerHigh = true;
+ b_oldIn = false;
+ m_value = 0;
+ b_en = false;
+ b_ud = false;
+ m_numBits = 0;
+ m_maxValue = false;
+ m_bDoneLogicIn = false;
+
+ createProperty( "trig", Variant::Type::Select );
+ property("trig")->setCaption( i18n("Trigger Edge") );
+ property("trig")->setAllowed( QStringList::split( ',', "Rising,Falling" ) );
+ property("trig")->setValue("Rising");
+
+ createProperty( "bitcount", Variant::Type::Int );
+ property("bitcount")->setCaption( i18n("Bit Count") );
+ property("bitcount")->setMinValue(1);
+ property("bitcount")->setMaxValue(26);
+ property("bitcount")->setValue(4);
+}
+
+
+BinaryCounter::~BinaryCounter()
+{
+}
+
+
+void BinaryCounter::dataChanged()
+{
+ initPins( dataInt("bitcount") );
+
+ b_triggerHigh = dataString("trig") == "Rising";
+ setDisplayText( ">", b_triggerHigh ? "^>" : "_>" );
+}
+
+
+void BinaryCounter::initPins( unsigned numBits )
+{
+ if ( m_numBits == numBits )
+ return;
+
+ QStringList pins;
+ pins << "en" << ">" << "u/d" << "r";
+
+ for ( int i = 0; i < QABS(4-int(numBits)); i++ )
+ pins << "";
+
+ for ( int i = numBits-1; i >= 0; i-- )
+ pins << QChar('A'+i);
+
+ initDIPSymbol( pins, 64 );
+ initDIP(pins);
+
+ if ( m_numBits < numBits )
+ {
+ for ( unsigned i = m_numBits; i < numBits; i++ )
+ m_pLogicOut[i] = createLogicOut( ecNodeWithID( QChar('A'+i) ), false );
+ }
+ else
+ {
+ for ( unsigned i = numBits; i < m_numBits; i++ )
+ {
+ QString id = QChar('A'+i);
+ removeElement( m_pLogicOut[i], false );
+ removeDisplayText(id);
+ removeNode(id);
+ }
+ }
+
+ m_numBits = numBits;
+ m_maxValue = (1<<m_numBits)-1;
+
+ if (!m_bDoneLogicIn)
+ {
+ enLogic = createLogicIn( ecNodeWithID("en") );
+ inLogic = createLogicIn( ecNodeWithID(">") );
+ rLogic = createLogicIn( ecNodeWithID("r") );
+ udLogic = createLogicIn( ecNodeWithID("u/d") );
+
+ enLogic->setCallback( this, (CallbackPtr)(&BinaryCounter::enStateChanged) );
+ inLogic->setCallback( this, (CallbackPtr)(&BinaryCounter::inStateChanged) );
+ rLogic->setCallback( this, (CallbackPtr)(&BinaryCounter::rStateChanged) );
+ udLogic->setCallback( this, (CallbackPtr)(&BinaryCounter::udStateChanged) );
+
+ m_bDoneLogicIn = true;
+ }
+
+ outputValue();
+}
+
+
+void BinaryCounter::inStateChanged( bool state )
+{
+ if ( (state != b_oldIn) && b_en && !b_reset && state == b_triggerHigh )
+ {
+ m_value += (b_ud) ? 1 : -1;
+
+ if ( m_value < 0 )
+ m_value = m_maxValue;
+
+ else if ( m_value > m_maxValue )
+ m_value = 0;
+
+ outputValue();
+ }
+
+ b_oldIn = state;
+}
+
+
+void BinaryCounter::rStateChanged( bool state )
+{
+ b_reset = state;
+ if (b_reset)
+ {
+ m_value = 0;
+ outputValue();
+ }
+}
+
+
+void BinaryCounter::enStateChanged( bool state )
+{
+ b_en = state;
+}
+
+
+void BinaryCounter::udStateChanged( bool state )
+{
+ b_ud = state;
+}
+
+
+void BinaryCounter::outputValue()
+{
+ for ( unsigned i = 0; i < m_numBits; i++ )
+ m_pLogicOut[i]->setHigh( m_value & (1 << i) );
+}
+
diff --git a/src/electronics/components/binarycounter.h b/src/electronics/components/binarycounter.h
new file mode 100644
index 0000000..b15762d
--- /dev/null
+++ b/src/electronics/components/binarycounter.h
@@ -0,0 +1,63 @@
+/***************************************************************************
+ * Copyright (C) 2003-2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef EC4BITCOUNTER_H
+#define EC4BITCOUNTER_H
+
+#include "component.h"
+#include "logic.h"
+
+/**
+Simple logic counter. 4 Inputs, 4 Outputs.
+
+Outputs (A-D) represent the stored value (0-15).
+The inputs are:
+@li en - Enable incrementing of value
+@li in - Input (trigger high)
+@li r - Reset stored value to 0
+@li ud - Up/Down increment
+
+@short 4 Bit Binary Counter
+@author David Saxton
+*/
+class BinaryCounter : public CallbackClass, public Component
+{
+public:
+ BinaryCounter( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~BinaryCounter();
+
+ virtual bool canFlip() const { return true; }
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+protected:
+ void inStateChanged( bool state ); // Input
+ void rStateChanged( bool state ); // Reset
+ void enStateChanged( bool state ); // Enable
+ void udStateChanged( bool state ); // Up/Down
+ void outputValue();
+ void dataChanged();
+ void initPins( unsigned numBits );
+
+ LogicIn *enLogic, *inLogic, *rLogic, *udLogic;
+ LogicOut * m_pLogicOut[26];
+
+ unsigned m_numBits;
+ bool b_triggerHigh;
+ bool b_en; // Enable
+ bool b_ud; // Up/Down
+ bool b_oldIn;
+ bool b_reset;
+ long m_value;
+ long m_maxValue;
+ bool m_bDoneLogicIn;
+};
+
+#endif
diff --git a/src/electronics/components/bussplitter.cpp b/src/electronics/components/bussplitter.cpp
new file mode 100644
index 0000000..62fbb39
--- /dev/null
+++ b/src/electronics/components/bussplitter.cpp
@@ -0,0 +1,133 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "bussplitter.h"
+#include "ecnode.h"
+#include "libraryitem.h"
+#include "wire.h"
+
+#include <klocale.h>
+#include <qpainter.h>
+
+Item* BusSplitter::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new BusSplitter( (ICNDocument*)itemDocument, newItem, id );
+}
+
+
+LibraryItem* BusSplitter::libraryItem()
+{
+ return new LibraryItem(
+ "ec/bus",
+ i18n("Bus"),
+ i18n("Connections"),
+ "bus.png",
+ LibraryItem::lit_component,
+ BusSplitter::construct );
+}
+
+
+const unsigned MAX_BUS_SIZE = 10000;
+
+
+BusSplitter::BusSplitter( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, id ? id : "Bus" )
+{
+ m_name = i18n("Bus Splitter");
+ m_desc = i18n("Merges several connections into one.");
+
+ m_busSize = 0;
+ init1PinLeft();
+ m_pInNode = m_pNNode[0];
+
+ createProperty( "size", Variant::Type::Int );
+ property("size")->setCaption( i18n("Size") );
+ property("size")->setMinValue(1);
+ property("size")->setMaxValue(MAX_BUS_SIZE);
+ property("size")->setValue(8);
+}
+
+
+BusSplitter::~BusSplitter()
+{
+}
+
+
+void BusSplitter::dataChanged()
+{
+ unsigned busSize = dataInt("size");
+
+ if ( busSize < 1 )
+ busSize = 1;
+
+ else if ( busSize > MAX_BUS_SIZE )
+ busSize = MAX_BUS_SIZE;
+
+ if ( busSize == m_busSize )
+ return;
+
+ m_pInNode->setNumPins(busSize);
+
+ if ( busSize > m_busSize )
+ {
+ m_pWires.resize(busSize);
+ for ( unsigned i = m_busSize; i < unsigned(busSize); i++ )
+ {
+ Pin * pin = createPin( 16, 0, 180, outNodeID(i) )->pin();
+ m_pWires[i] = new Wire( m_pInNode->pin(i), pin );
+ }
+ }
+ else
+ {
+ for ( unsigned i = busSize; i < unsigned(m_busSize); i++ )
+ {
+ removeNode( outNodeID(i) );
+ delete m_pWires[i];
+ }
+ m_pWires.resize(busSize);
+ }
+ m_busSize = busSize;
+
+ // Position pins
+ setSize( 0, -int(m_busSize+1)*8, 8, int(m_busSize+1)*16, true );
+ for ( int i = 0; i < int(m_busSize); i++ )
+ m_nodeMap[ outNodeID(i) ].y = 16*i - int(m_busSize+1)*8 + 24;
+ m_nodeMap["n1"].y = -int(m_busSize+1)*8 + 8;
+
+ updateAttachedPositioning();
+}
+
+
+QString BusSplitter::outNodeID( unsigned node ) const
+{
+ return QString("out_%1").arg(QString::number(node));
+}
+
+
+void BusSplitter::drawShape( QPainter &p )
+{
+ initPainter(p);
+
+// QPen pen(p.pen());
+// pen.setWidth();
+// p.setPen(pen);
+
+ int _x = int(x());
+ int _y = int(y());
+
+ QRect r = m_sizeRect;
+ r.moveBy( _x, _y );
+ p.drawRect(r);
+
+ deinitPainter(p);
+}
+
+
+
diff --git a/src/electronics/components/bussplitter.h b/src/electronics/components/bussplitter.h
new file mode 100644
index 0000000..ccd1994
--- /dev/null
+++ b/src/electronics/components/bussplitter.h
@@ -0,0 +1,45 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef BUSSPLITTER_H
+#define BUSSPLITTER_H
+
+#include <component.h>
+
+#include <qguardedptr.h>
+#include <qvaluevector.h>
+
+class Wire;
+
+/**
+@author David Saxton
+*/
+class BusSplitter : public Component
+{
+ public:
+ BusSplitter( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~BusSplitter();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+ virtual bool canFlip() const { return true; }
+
+ protected:
+ QString outNodeID( unsigned node ) const;
+ virtual void dataChanged();
+ virtual void drawShape( QPainter &p );
+
+ unsigned m_busSize;
+ QValueVector<QGuardedPtr<Wire> > m_pWires;
+ ECNode * m_pInNode;
+};
+
+#endif
diff --git a/src/electronics/components/demultiplexer.cpp b/src/electronics/components/demultiplexer.cpp
new file mode 100644
index 0000000..8a01808
--- /dev/null
+++ b/src/electronics/components/demultiplexer.cpp
@@ -0,0 +1,175 @@
+/***************************************************************************
+ * Copyright (C) 2004-2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "demultiplexer.h"
+
+#include "logic.h"
+#include "libraryitem.h"
+
+#include <kiconloader.h>
+#include <klocale.h>
+
+#include <cmath>
+
+Item* Demultiplexer::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new Demultiplexer( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* Demultiplexer::libraryItem()
+{
+ return new LibraryItem(
+ "ec/demultiplexer",
+ i18n("Demultiplexer"),
+ i18n("Integrated Circuits"),
+ "ic1.png",
+ LibraryItem::lit_component,
+ Demultiplexer::construct
+ );
+}
+
+Demultiplexer::Demultiplexer( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, id ? id : "demultiplexer" )
+{
+ m_name = i18n("Demultiplexer");
+ m_desc = i18n("Seperates the input data stream into components. The value of the input is passed to the \"X\" output selected by the binary number given by the \"A\" inputs.");
+
+ m_input = 0l;
+
+ createProperty( "addressSize", Variant::Type::Int );
+ property("addressSize")->setCaption( i18n("Address Size") );
+ property("addressSize")->setMinValue(1);
+ property("addressSize")->setMaxValue(8);
+ property("addressSize")->setValue(1);
+
+ // For backwards compatibility
+ createProperty( "numInput", Variant::Type::Int );
+ property("numInput")->setMinValue(-1);
+ property("numInput")->setValue(-1);
+ property("numInput")->setHidden(true);
+}
+
+Demultiplexer::~Demultiplexer()
+{
+}
+
+
+void Demultiplexer::dataChanged()
+{
+ if ( hasProperty("numInput") && dataInt("numInput") != -1 )
+ {
+ int addressSize = int( std::ceil( std::log( (double)dataInt("numInput") ) / std::log(2.0) ) );
+ property("numInput")->setValue(-1);
+
+ if ( addressSize < 1 )
+ addressSize = 1;
+ else if ( addressSize > 8 )
+ addressSize = 8;
+
+ // This function will get called again when we set the value of numInput
+ property("addressSize")->setValue(addressSize);
+ return;
+ }
+
+ if ( hasProperty("numInput") )
+ {
+ m_variantData["numInput"]->deleteLater();
+ m_variantData.remove("numInput");
+ }
+
+ initPins( unsigned(dataInt("addressSize")) );
+}
+
+
+void Demultiplexer::inStateChanged( bool /*state*/ )
+{
+ unsigned long long pos = 0;
+ for ( unsigned i = 0; i < m_aLogic.size(); ++i )
+ {
+ if ( m_aLogic[i]->isHigh() )
+ pos += 1 << i;
+ }
+ for ( unsigned i = 0; i < m_xLogic.size(); ++i )
+ m_xLogic[i]->setHigh( (pos == i) && m_input->isHigh() );
+}
+
+
+void Demultiplexer::initPins( unsigned newAddressSize )
+{
+ unsigned oldAddressSize = m_aLogic.size();
+ unsigned long long oldXLogicCount = m_xLogic.size();
+ unsigned long long newXLogicCount = 1 << newAddressSize;
+
+ if ( newXLogicCount == oldXLogicCount )
+ return;
+
+ QStringList pins;
+
+ for ( unsigned i=0; i<newAddressSize; ++i )
+ pins += "A"+QString::number(i);
+ for ( unsigned i=newAddressSize; i<(newXLogicCount+(newXLogicCount%2))/2; ++i )
+ pins += "";
+ pins += "X";
+ for ( unsigned i=(newXLogicCount+(newXLogicCount%2))/2+1; i<newXLogicCount; ++i )
+ pins += "";
+ for ( int i=newXLogicCount-1; i>=0; --i )
+ pins += "X"+QString::number(i);
+
+ initDIPSymbol( pins, 64 );
+ initDIP(pins);
+
+ ECNode *node;
+
+ if (!m_input)
+ {
+ node = ecNodeWithID("X");
+ m_input = createLogicIn(node);
+ m_input->setCallback( this, (CallbackPtr)(&Demultiplexer::inStateChanged) );
+ }
+
+ if ( newXLogicCount > oldXLogicCount )
+ {
+ m_xLogic.resize(newXLogicCount);
+ for ( unsigned i = oldXLogicCount; i < newXLogicCount; ++i )
+ {
+ node = ecNodeWithID("X"+QString::number(i));
+ m_xLogic.insert( i, createLogicOut(node,false) );
+ }
+
+ m_aLogic.resize(newAddressSize);
+ for ( unsigned i = oldAddressSize; i < newAddressSize; ++i )
+ {
+ node = ecNodeWithID("A"+QString::number(i));
+ m_aLogic.insert( i, createLogicIn(node) );
+ m_aLogic[i]->setCallback( this, (CallbackPtr)(&Demultiplexer::inStateChanged) );
+ }
+ }
+ else
+ {
+ for ( unsigned i = newXLogicCount; i < oldXLogicCount; ++i )
+ {
+ QString id = "X"+QString::number(i);
+ removeDisplayText(id);
+ removeElement( m_xLogic[i], false );
+ removeNode(id);
+ }
+ m_xLogic.resize(newXLogicCount);
+
+ for ( unsigned i = newAddressSize; i < oldAddressSize; ++i )
+ {
+ QString id = "A"+QString::number(i);
+ removeDisplayText(id);
+ removeElement( m_aLogic[i], false );
+ removeNode(id);
+ }
+ m_aLogic.resize(newAddressSize);
+ }
+}
+
diff --git a/src/electronics/components/demultiplexer.h b/src/electronics/components/demultiplexer.h
new file mode 100644
index 0000000..a2b52dd
--- /dev/null
+++ b/src/electronics/components/demultiplexer.h
@@ -0,0 +1,46 @@
+/***************************************************************************
+ * Copyright (C) 2004-2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef DEMULTIPLEXER_H
+#define DEMULTIPLEXER_H
+
+#include "component.h"
+#include "logic.h"
+
+#include <qptrvector.h>
+
+/**
+@author David Saxton
+*/
+class Demultiplexer : public CallbackClass, public Component
+{
+public:
+ Demultiplexer( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~Demultiplexer();
+
+ virtual bool canFlip() const { return true; }
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+protected:
+ void dataChanged();
+ /**
+ * Add / remove pins according to the number of inputs the user has requested
+ */
+ void initPins( unsigned addressSize );
+
+ void inStateChanged( bool newState );
+
+ QPtrVector<LogicIn> m_aLogic;
+ QPtrVector<LogicOut> m_xLogic;
+ LogicIn * m_input;
+};
+
+#endif
diff --git a/src/electronics/components/dependentsource.cpp b/src/electronics/components/dependentsource.cpp
new file mode 100644
index 0000000..764cc53
--- /dev/null
+++ b/src/electronics/components/dependentsource.cpp
@@ -0,0 +1,314 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "dependentsource.h"
+#include "ecnode.h"
+#include "libraryitem.h"
+#include "pin.h"
+
+#include "cccs.h"
+#include "ccvs.h"
+#include "vccs.h"
+#include "vcvs.h"
+
+#include <klocale.h>
+#include <qpainter.h>
+
+//BEGIN class DependentSource
+DependentSource::DependentSource( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, id )
+{
+ setSize( -16, -16, 32, 32 );
+
+ init2PinLeft();
+ init2PinRight();
+
+ createProperty( "gain", Variant::Type::Double );
+ property("gain")->setCaption( i18n("Gain") );
+ property("gain")->setValue(1.0);
+
+ addDisplayText( "gain", QRect( -16, -32, 32, 16 ), "" );
+}
+
+
+DependentSource::~DependentSource()
+{
+}
+
+
+void DependentSource::drawOutline( QPainter & p )
+{
+ const int _x = (int)x()-16;
+ const int _y = (int)y()-32;
+
+ // Top rectangle
+ p.drawRect( _x, _y+19, width(), 11 );
+
+ p.save();
+ bool canSetCol = (p.pen().color() != Qt::color0) && (p.pen().color() != Qt::color1);
+
+ // Bottom lines
+ if (canSetCol)
+ p.setPen( m_pNNode[1]->isSelected() ? m_selectedCol : Qt::black );
+ p.drawLine( _x, _y+40, _x+8, _y+40 ); // Left inny
+
+ if (canSetCol)
+ p.setPen( m_pPNode[1]->isSelected() ? m_selectedCol : Qt::black );
+ p.drawLine( _x+width(), _y+40, _x+24, _y+40 ); // Right inny
+
+ p.restore();
+
+ // Bottom diamond
+ QPointArray pa4(4);
+ pa4[0] = QPoint( _x+6, _y+40 );
+ pa4[1] = QPoint( _x+16, _y+32 );
+ pa4[2] = QPoint( _x+26, _y+40 );
+ pa4[3] = QPoint( _x+16, _y+48 );
+ p.drawPolygon(pa4);
+}
+
+
+void DependentSource::drawTopArrow( QPainter & p )
+{
+ const int _x = (int)x()-16;
+ const int _y = (int)y()-32;
+
+ if ( p.pen().color() == m_selectedCol )
+ p.setPen(Qt::black);
+
+ if ( p.brush().color() == m_brushCol )
+ p.setBrush(Qt::black);
+
+ p.drawLine( _x+8, _y+24, _x+24, _y+24 );
+
+ QPointArray pa3(3);
+ pa3[0] = QPoint( _x+24, _y+24 );
+ pa3[1] = QPoint( _x+19, _y+21 );
+ pa3[2] = QPoint( _x+19, _y+27 );
+ p.drawPolygon(pa3);
+}
+
+
+void DependentSource::drawBottomArrow( QPainter & p )
+{
+ const int _x = (int)x()-16;
+ const int _y = (int)y()-32;
+
+ if ( p.pen().color() == m_selectedCol )
+ p.setPen(Qt::black);
+
+ if ( p.brush().color() == m_brushCol )
+ p.setBrush(Qt::black);
+
+ p.drawLine( _x+11, _y+40, _x+21, _y+40 );
+
+ QPointArray pa3(3);
+ pa3[0] = QPoint( _x+21, _y+40 );
+ pa3[1] = QPoint( _x+16, _y+37 );
+ pa3[2] = QPoint( _x+16, _y+43 );
+ p.drawPolygon(pa3);
+}
+//END class DependentSource
+
+
+//BEGIN class ECCCCS
+Item* ECCCCS::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECCCCS( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ECCCCS::libraryItem()
+{
+ return new LibraryItem(
+ QString("ec/cccs"),
+ i18n("CCCS"),
+ i18n("Sources"),
+ "cccs.png",
+ LibraryItem::lit_component,
+ ECCCCS::construct );
+}
+
+ECCCCS::ECCCCS( ICNDocument *icnDocument, bool newItem, const char *id )
+ : DependentSource( icnDocument, newItem, id ? id : "cccs" )
+{
+ m_name = i18n("Current Controlled Currrent Source");
+ m_cccs = createCCCS( m_pNNode[0], m_pPNode[0], m_pNNode[1], m_pPNode[1], 1. );
+ m_pNNode[1]->pin()->setGroundType( Pin::gt_medium );
+}
+
+ECCCCS::~ECCCCS()
+{
+}
+
+void ECCCCS::dataChanged()
+{
+ double gain = dataDouble("gain");
+
+ QString display = QString::number( gain / getMultiplier(gain), 'g', 3 ) + getNumberMag(gain) + QChar(' ');
+ setDisplayText( "gain", display );
+
+ m_cccs->setGain(gain);
+}
+
+void ECCCCS::drawShape( QPainter &p )
+{
+ initPainter(p);
+ drawOutline(p);
+ drawTopArrow(p);
+ drawBottomArrow(p);
+ deinitPainter(p);
+}
+//END class ECCCCS
+
+
+//BEGIN class ECCCVS
+Item* ECCCVS::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECCCVS( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ECCCVS::libraryItem()
+{
+ return new LibraryItem(
+ QString("ec/ccvs"),
+ i18n("CCVS"),
+ i18n("Sources"),
+ "ccvs.png",
+ LibraryItem::lit_component,
+ ECCCVS::construct );
+}
+
+ECCCVS::ECCCVS( ICNDocument *icnDocument, bool newItem, const char *id )
+ : DependentSource( icnDocument, newItem, id ? id : "ccvs" )
+{
+ m_name = i18n("Current Controlled Voltage Source");
+ m_ccvs = createCCVS( m_pNNode[0], m_pPNode[0], m_pNNode[1], m_pPNode[1], 1. );
+ m_pNNode[1]->pin()->setGroundType( Pin::gt_medium );
+}
+
+ECCCVS::~ECCCVS()
+{
+}
+
+void ECCCVS::dataChanged()
+{
+ double gain = dataDouble("gain");
+
+ QString display = QString::number( gain / getMultiplier(gain), 'g', 3 ) + getNumberMag(gain) + QChar(' ');
+ setDisplayText( "gain", display );
+
+ m_ccvs->setGain(gain);
+}
+
+void ECCCVS::drawShape( QPainter &p )
+{
+ initPainter(p);
+ drawOutline(p);
+ drawTopArrow(p);
+ deinitPainter(p);
+}
+//END class ECCCVS
+
+
+//BEGIN class ECVCCS
+Item* ECVCCS::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECVCCS( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ECVCCS::libraryItem()
+{
+ return new LibraryItem(
+ QString("ec/vccs"),
+ i18n("VCCS"),
+ i18n("Sources"),
+ "vccs.png",
+ LibraryItem::lit_component,
+ ECVCCS::construct );
+}
+
+ECVCCS::ECVCCS( ICNDocument *icnDocument, bool newItem, const char *id )
+ : DependentSource( icnDocument, newItem, id ? id : "vccs" )
+{
+ m_name = i18n("Voltage Controlled Current Source");
+ m_vccs = createVCCS( m_pNNode[0], m_pPNode[0], m_pNNode[1], m_pPNode[1], 1. );
+ m_pNNode[1]->pin()->setGroundType( Pin::gt_medium );
+}
+
+ECVCCS::~ECVCCS()
+{
+}
+
+void ECVCCS::dataChanged()
+{
+ double gain = dataDouble("gain");
+
+ QString display = QString::number( gain / getMultiplier(gain), 'g', 3 ) + getNumberMag(gain) + QChar(' ');
+ setDisplayText( "gain", display );
+
+ m_vccs->setGain(gain);
+}
+
+void ECVCCS::drawShape( QPainter &p )
+{
+ initPainter(p);
+ drawOutline(p);
+ drawBottomArrow(p);
+ deinitPainter(p);
+}
+//END class ECVCCS
+
+
+//BEGIN class ECVCVS
+Item* ECVCVS::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECVCVS( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ECVCVS::libraryItem()
+{
+ return new LibraryItem(
+ QString("ec/vcvs"),
+ i18n("VCVS"),
+ i18n("Sources"),
+ "vcvs.png",
+ LibraryItem::lit_component,
+ ECVCVS::construct );
+}
+
+ECVCVS::ECVCVS( ICNDocument *icnDocument, bool newItem, const char *id )
+ : DependentSource( icnDocument, newItem, id ? id : "vcvs" )
+{
+ m_name = i18n("Voltage Controlled Voltage Source");
+ m_vcvs = createVCVS( m_pNNode[0], m_pPNode[0], m_pNNode[1], m_pPNode[1], 1. );
+ m_pNNode[1]->pin()->setGroundType( Pin::gt_medium );
+}
+
+ECVCVS::~ECVCVS()
+{
+}
+
+void ECVCVS::dataChanged()
+{
+ double gain = dataDouble("gain");
+
+ QString display = QString::number( gain / getMultiplier(gain), 'g', 3 ) + getNumberMag(gain) + QChar(' ');
+ setDisplayText( "gain", display );
+
+ m_vcvs->setGain(gain);
+}
+
+void ECVCVS::drawShape( QPainter &p )
+{
+ initPainter(p);
+ drawOutline(p);
+ deinitPainter(p);
+}
+//END class ECVCVS
diff --git a/src/electronics/components/dependentsource.h b/src/electronics/components/dependentsource.h
new file mode 100644
index 0000000..2bccbb7
--- /dev/null
+++ b/src/electronics/components/dependentsource.h
@@ -0,0 +1,112 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef DEPENDENTSOURCE_H
+#define DEPENDENTSOURCE_H
+
+#include "component.h"
+
+/**
+@author David Saxton
+*/
+class DependentSource : public Component
+{
+ public:
+ DependentSource( ICNDocument *icnDocument, bool newItem, const char *id );
+ ~DependentSource();
+ virtual bool canFlip() const { return true; }
+
+ protected:
+ void drawOutline( QPainter & p );
+ void drawTopArrow( QPainter & p );
+ void drawBottomArrow( QPainter & p );
+};
+
+/**
+@short Current Controlled Current Source
+@author David Saxton
+*/
+class ECCCCS : public DependentSource
+{
+ public:
+ ECCCCS( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECCCCS();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+ protected:
+ virtual void dataChanged();
+ virtual void drawShape( QPainter &p );
+
+ CCCS *m_cccs;
+};
+
+/**
+@short Current Controlled Voltage Source
+@author David Saxton
+*/
+class ECCCVS : public DependentSource
+{
+ public:
+ ECCCVS( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECCCVS();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+ protected:
+ virtual void dataChanged();
+ virtual void drawShape( QPainter &p );
+
+ CCVS *m_ccvs;
+};
+
+/**
+@short Voltage Controlled Current Source
+@author David Saxton
+*/
+class ECVCCS : public DependentSource
+{
+ public:
+ ECVCCS( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECVCCS();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+ protected:
+ virtual void dataChanged();
+ virtual void drawShape( QPainter &p );
+
+ VCCS *m_vccs;
+};
+
+/**
+@short Voltage Controlled Voltage Source
+@author David Saxton
+*/
+class ECVCVS : public DependentSource
+{
+ public:
+ ECVCVS( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECVCVS();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+ protected:
+ virtual void dataChanged();
+ virtual void drawShape( QPainter &p );
+
+ VCVS *m_vcvs;
+};
+
+#endif
diff --git a/src/electronics/components/discretelogic.cpp b/src/electronics/components/discretelogic.cpp
new file mode 100644
index 0000000..e2e284e
--- /dev/null
+++ b/src/electronics/components/discretelogic.cpp
@@ -0,0 +1,308 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "canvasitemparts.h"
+#include "discretelogic.h"
+#include "ecnode.h"
+#include "logic.h"
+#include "libraryitem.h"
+#include "simulator.h"
+
+#include <klocale.h>
+#include <qpainter.h>
+
+
+//BEGIN class Inverter
+Item* Inverter::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new Inverter( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* Inverter::libraryItem()
+{
+ QStringList ids;
+ ids << "ec/inverter" << "ec/not";
+ return new LibraryItem(
+ ids,
+ i18n("Inverter"),
+ i18n("Logic"),
+ "not.png",
+ LibraryItem::lit_component,
+ Inverter::construct );
+}
+
+Inverter::Inverter( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, id ? id : "not" )
+{
+ m_name = i18n("Inverter");
+ m_desc = i18n("The output is the logical inverse of the logic-input state.");
+ setSize( -8, -8, 16, 16 );
+
+ init1PinLeft();
+ init1PinRight();
+
+ m_pIn = createLogicIn(m_pNNode[0]);
+ m_pOut = createLogicOut( m_pPNode[0], true );
+
+ m_pIn->setCallback( this, (CallbackPtr)(&Inverter::inStateChanged) );
+ inStateChanged(false);
+}
+
+
+Inverter::~Inverter()
+{
+}
+
+
+void Inverter::inStateChanged( bool newState )
+{
+ (static_cast<LogicOut*>(m_pOut))->setHigh( !newState );
+}
+
+
+void Inverter::drawShape( QPainter &p )
+{
+ initPainter(p);
+ int _x = (int)x()-8;
+ int _y = (int)y()-8;
+ QPointArray pa(3);
+ pa[0] = QPoint( _x, _y );
+ pa[1] = QPoint( _x+width()-6, _y+(height()/2) );
+ pa[2] = QPoint( _x, _y+height() );
+ p.drawPolygon(pa);
+ p.drawPolyline(pa);
+ p.drawEllipse( _x+width()-6, _y+(height()/2)-3, 7, 7 );
+ deinitPainter(p);
+}
+//END class Inverter
+
+
+//BEGIN class Buffer
+Item* Buffer::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new Buffer( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* Buffer::libraryItem()
+{
+ return new LibraryItem(
+ QString::QString("ec/buffer"),
+ i18n("Buffer"),
+ i18n("Logic"),
+ "buffer.png",
+ LibraryItem::lit_component,
+ Buffer::construct );
+}
+
+Buffer::Buffer( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, id ? id : "buffer" )
+{
+ m_name = i18n("Buffer");
+ m_desc = i18n("Cleans the logic input, with the output high or low depending on input trigger levels.");
+ setSize( -8, -8, 16, 16 );
+
+ init1PinLeft();
+ init1PinRight();
+
+ m_pIn = createLogicIn(m_pNNode[0]);
+ m_pOut = createLogicOut( m_pPNode[0], true );
+
+ m_pIn->setCallback( this, (CallbackPtr)(&Buffer::inStateChanged) );
+ inStateChanged(false);
+}
+
+
+Buffer::~Buffer()
+{
+}
+
+
+void Buffer::inStateChanged( bool newState )
+{
+ m_pOut->setHigh(newState);
+}
+
+
+void Buffer::drawShape( QPainter &p )
+{
+ initPainter(p);
+ int _x = (int)x()-8;
+ int _y = (int)y()-8;
+ QPointArray pa(3);
+ pa[0] = QPoint( _x, _y );
+ pa[1] = QPoint( _x+width(), _y+(height()/2) );
+ pa[2] = QPoint( _x, _y+height() );
+ p.drawPolygon(pa);
+ p.drawPolyline(pa);
+ deinitPainter(p);
+}
+//END class Buffer
+
+
+//BEGIN class ECLogicInput
+Item* ECLogicInput::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECLogicInput( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ECLogicInput::libraryItem()
+{
+ return new LibraryItem(
+ QString::QString("ec/logic_input"),
+ i18n("Logic Input"),
+ i18n("Logic"),
+ "logic_input.png",
+ LibraryItem::lit_component,
+ ECLogicInput::construct );
+}
+
+ECLogicInput::ECLogicInput( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, (id) ? id : "logic_input" )
+{
+ m_name = i18n("Logic Input");
+ m_desc = i18n("Provides a user-adjustable logic state.<br><br>"
+ "Click to pulse high, or drag the mouse off to keep the output high.");
+ setSize( -8, -8, 16, 16 );
+
+ b_state = false;
+ addButton( "button", QRect( -24, -8, 16, 16 ), "", true );
+
+ createProperty( "useToggle", Variant::Type::Bool );
+ property("useToggle")->setCaption( i18n("Use Toggle") );
+ property("useToggle")->setValue(true);
+
+ init1PinRight();
+
+ m_pOut = createLogicOut( m_pPNode[0], false );
+}
+
+
+ECLogicInput::~ECLogicInput()
+{
+}
+
+
+void ECLogicInput::dataChanged()
+{
+ button("button")->setToggle( dataBool("useToggle") );
+}
+
+
+void ECLogicInput::drawShape( QPainter &p )
+{
+ initPainter(p);
+ if (b_state)
+ p.setBrush( QColor( 255, 166, 0 ) );
+ else
+ p.setBrush( Qt::white );
+ p.drawEllipse( (int)x()-4, (int)y()-6, 12, 12 );
+ deinitPainter(p);
+}
+
+
+void ECLogicInput::buttonStateChanged( const QString &, bool state )
+{
+ b_state = state;
+ m_pOut->setHigh(b_state);
+}
+//END class ECLogicInput
+
+
+//BEGIN class ECLogicOutput
+Item* ECLogicOutput::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECLogicOutput( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ECLogicOutput::libraryItem()
+{
+ return new LibraryItem(
+ QString::QString("ec/logic_output"),
+ i18n("Logic Output"),
+ i18n("Logic"),
+ "logic_output.png",
+ LibraryItem::lit_component,
+ ECLogicOutput::construct );
+}
+
+ECLogicOutput::ECLogicOutput( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, (id) ? id : "logic_output" )
+{
+ m_name = i18n("Logic Output");
+ m_desc = i18n("Shows the logic-state of the input.");
+ setSize( -8, -8, 16, 16 );
+
+ init1PinLeft();
+ m_pIn = createLogicIn(m_pNNode[0]);
+
+ m_pSimulator = Simulator::self();
+
+ m_lastDrawState = 0.0;
+ m_lastSwitchTime = m_lastDrawTime = m_pSimulator->time();
+ m_highTime = 0;
+ m_bLastState = false;
+ m_bDynamicContent = true;
+
+ m_pIn->setCallback( this, (CallbackPtr)(&ECLogicOutput::inStateChanged) );
+}
+
+ECLogicOutput::~ECLogicOutput()
+{
+}
+
+void ECLogicOutput::inStateChanged( bool newState )
+{
+ if ( m_bLastState == newState )
+ return;
+
+ unsigned long long newTime = m_pSimulator->time();
+ unsigned long long dt = newTime - m_lastSwitchTime;
+
+ m_lastSwitchTime = newTime;
+
+ m_bLastState = newState;
+ if (!newState)
+ {
+ // Gone from high to low
+ m_highTime += dt;
+ }
+}
+
+
+void ECLogicOutput::drawShape( QPainter &p )
+{
+ unsigned long long newTime = m_pSimulator->time();
+ unsigned long long runTime = newTime - m_lastDrawTime;
+ m_lastDrawTime = newTime;
+
+ if (m_bLastState)
+ {
+ // Logic in is currently high
+ m_highTime += newTime - m_lastSwitchTime;
+ }
+
+ double state;
+
+ if ( runTime == 0 )
+ state = m_lastDrawState;
+
+ else
+ state = m_lastDrawState = double(m_highTime)/double(runTime);
+
+ initPainter(p);
+ p.setBrush( QColor( 255, uint(255-state*(255-166)), uint((1-state)*255) ) );
+ p.drawEllipse( int(x()-8), int(y()-8), width(), height() );
+ deinitPainter(p);
+
+ m_lastSwitchTime = newTime;
+ m_highTime = 0;
+}
+//END class ECLogicOutput
+
diff --git a/src/electronics/components/discretelogic.h b/src/electronics/components/discretelogic.h
new file mode 100644
index 0000000..82775bf
--- /dev/null
+++ b/src/electronics/components/discretelogic.h
@@ -0,0 +1,110 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef DISCRETELOGIC_H
+#define DISCRETELOGIC_H
+
+#include "component.h"
+#include "logic.h"
+
+class Simulator;
+
+/**
+@short Boolean NOT
+@author David Saxton
+*/
+class Inverter : public CallbackClass, public Component
+{
+ public:
+ Inverter( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~Inverter();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+ protected:
+ void inStateChanged( bool newState );
+ virtual void drawShape( QPainter &p );
+
+ LogicIn * m_pIn;
+ LogicOut * m_pOut;
+};
+
+/**
+@short Buffer
+@author David Saxton
+*/
+class Buffer : public CallbackClass, public Component
+{
+public:
+ Buffer( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~Buffer();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+private:
+ void inStateChanged( bool newState );
+ virtual void drawShape( QPainter &p );
+
+ LogicIn * m_pIn;
+ LogicOut * m_pOut;
+};
+
+/**
+@short Boolean logic input
+@author David Saxton
+*/
+class ECLogicInput : public Component
+{
+public:
+ ECLogicInput( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECLogicInput();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+ virtual void buttonStateChanged( const QString &id, bool state );
+
+private:
+ virtual void dataChanged();
+ virtual void drawShape( QPainter &p );
+ LogicOut * m_pOut;
+ bool b_state;
+};
+
+/**
+@short Boolean logic output
+@author David Saxton
+*/
+class ECLogicOutput : public CallbackClass, public Component
+{
+ public:
+ ECLogicOutput( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECLogicOutput();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+ protected:
+ void inStateChanged( bool newState );
+ virtual void drawShape( QPainter &p );
+
+ unsigned long long m_lastDrawTime;
+ unsigned long long m_lastSwitchTime;
+ unsigned long long m_highTime;
+ bool m_bLastState;
+
+ double m_lastDrawState;
+ LogicIn * m_pIn;
+ Simulator * m_pSimulator;
+};
+
+#endif
diff --git a/src/electronics/components/ec555.cpp b/src/electronics/components/ec555.cpp
new file mode 100644
index 0000000..eccf2bd
--- /dev/null
+++ b/src/electronics/components/ec555.cpp
@@ -0,0 +1,172 @@
+/***************************************************************************
+ * Copyright (C) 2003 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "ec555.h"
+
+#include "ecnode.h"
+#include "libraryitem.h"
+#include "pin.h"
+#include "resistance.h"
+
+#include <kiconloader.h>
+#include <klocale.h>
+#include <qpainter.h>
+
+Item* EC555::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new EC555( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* EC555::libraryItem()
+{
+ return new LibraryItem(
+ QString::QString("ec/555"),
+ i18n("555"),
+ i18n("Integrated Circuits"),
+ "ic1.png",
+ LibraryItem::lit_component,
+ EC555::construct
+ );
+}
+
+EC555::EC555( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, (id) ? id : "555" )
+{
+ m_name = i18n("555");
+ m_desc = i18n("Common timer IC");
+// m_pins = QStringList::split( ',', "Gnd,Trg,Out,Res,CV,Th,Dis,Vcc" );
+// m_pins = QStringList::split( ',', "Dis,Th,Trg,Gnd,CV,Out,Res,Vcc" );
+
+ old_com1 = false;
+ old_com2 = false;
+ old_q = false;
+
+ setSize( -32, -32, 64, 64 );
+
+
+ // Pins down left
+
+ // Pin 7
+ discharge = createPin( -40, -16, 0, "Dis" )->pin();
+ addDisplayText( "dis", QRect( -32, -24, 24, 16 ), "Dis" );
+
+ // Pin 6
+ threshold = createPin( -40, 0, 0, "Th" )->pin();
+ addDisplayText( "th", QRect( -32, -8, 24, 16 ), "Th" );
+
+ // Pin 2
+ trigger = createPin( -40, 16, 0, "Trg" )->pin();
+ addDisplayText( "trg", QRect( -32, 8, 24, 16 ), "Trg" );
+
+
+
+ // Top two
+
+ // Pin 8
+ vcc = createPin( -16, -40, 90, "Vcc" )->pin();
+ addDisplayText( "vcc", QRect( -24, -32, 16, 8 ), "+" );
+
+ // Pin 4
+ reset = createPin( 16, -40, 90, "Res" )->pin();
+ addDisplayText( "res", QRect( 8, -28, 16, 16 ), "Res" );
+
+
+
+ // Bottom two
+
+ // Pin 1
+ ground = createPin( -16, 40, 270, "Gnd" )->pin();
+ addDisplayText( "gnd", QRect( -24, 20, 16, 8 ), "-" );
+
+ // Pin 5
+ control = createPin( 16, 40, 270, "CV" )->pin();
+ addDisplayText( "cv", QRect( 8, 12, 16, 16 ), "CV" );
+
+
+
+ // Output on right
+
+ // Pin 3
+ output = createPin( 40, 0, 180, "Out" )->pin();
+ addDisplayText( "out", QRect( 8, -8, 16, 16 ), "Out" );
+
+
+
+ m_r1 = createResistance( vcc, control, 5e3 );
+ m_r23 = createResistance( control, ground, 1e4 );
+ m_po_sink = createResistance( output, ground, 0. );
+ m_po_source = createResistance( output, vcc, 0. );
+ m_po_source->setConductance(0.);
+ m_r_discharge = createResistance( discharge, ground, 0. );
+}
+
+
+EC555::~EC555()
+{
+}
+
+void EC555::stepNonLogic()
+{
+ double v_threshold = threshold->voltage();
+ double v_control = control->voltage();
+ double v_ground = ground->voltage();
+ double v_trigger = trigger->voltage();
+ double v_reset = reset->voltage();
+ double v_vcc = vcc->voltage();
+
+ double v_r = (v_control+v_ground)/2;
+
+ bool com1 = ( v_threshold == v_control ) ? old_com1 : ( v_threshold < v_control );
+ bool com2 = ( v_r == v_trigger ) ? old_com2 : ( v_r > v_trigger );
+ bool reset = ( v_reset >= (v_control-v_ground)/2 + v_ground );
+ old_com1 = com1;
+ old_com2 = com2;
+
+ bool r = ( !reset || !com1 );
+ bool s = com2;
+
+ bool q = old_q;
+ if ( v_vcc - v_ground >= 2.5 )
+ {
+ if ( s && !r )
+ {
+ q = true;
+ }
+ else if ( r && !s )
+ {
+ q = false;
+ }
+ }
+ else
+ {
+ q = false;
+ }
+ old_q = q;
+
+
+ m_r_discharge->setConductance(0.);
+
+ if (q)
+ {
+ m_po_source->setResistance(10.);
+ m_po_sink->setConductance(0.);
+ }
+ else
+ {
+ m_po_source->setConductance(0.);
+ m_po_sink->setResistance(10.);
+ if ( v_ground+0.7 <= v_vcc )
+ {
+ m_r_discharge->setResistance(10.);
+ }
+ }
+}
+
+
diff --git a/src/electronics/components/ec555.h b/src/electronics/components/ec555.h
new file mode 100644
index 0000000..edeb2a5
--- /dev/null
+++ b/src/electronics/components/ec555.h
@@ -0,0 +1,56 @@
+/***************************************************************************
+ * Copyright (C) 2003 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef EC555_H
+#define EC555_H
+
+#include "component.h"
+
+#include <qstringlist.h>
+
+/**
+@short 555 IC
+@author David Saxton
+*/
+class EC555 : public Component
+{
+public:
+ EC555( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~EC555();
+
+ virtual bool canFlip() const { return true; }
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+ virtual void stepNonLogic();
+ virtual bool doesStepNonLogic() const { return true; }
+
+private:
+ Pin * ground;
+ Pin * trigger;
+ Pin * output;
+ Pin * reset;
+ Pin * control;
+ Pin * threshold;
+ Pin * discharge;
+ Pin * vcc;
+
+ Resistance *m_r1;
+ Resistance *m_r23;
+ Resistance *m_po_sink;
+ Resistance *m_po_source;
+ Resistance *m_r_discharge;
+
+ bool old_com1;
+ bool old_com2;
+ bool old_q;
+};
+
+#endif
diff --git a/src/electronics/components/ecbcdto7segment.cpp b/src/electronics/components/ecbcdto7segment.cpp
new file mode 100644
index 0000000..fb210ea
--- /dev/null
+++ b/src/electronics/components/ecbcdto7segment.cpp
@@ -0,0 +1,158 @@
+/***************************************************************************
+ * Copyright (C) 2003-2004 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "ecbcdto7segment.h"
+
+#include "logic.h"
+#include "libraryitem.h"
+
+#include <kiconloader.h>
+#include <klocale.h>
+
+// Values for a,b,c,d,e,f,g of common-anode 7 segment display
+bool numbers[16][7] =
+ { { 1, 1, 1, 1, 1, 1, 0 }, // 0
+ { 0, 1, 1, 0, 0, 0, 0 }, // 1
+ { 1, 1, 0, 1, 1, 0, 1 }, // 2
+ { 1, 1, 1, 1, 0, 0, 1 }, // 3
+ { 0, 1, 1, 0 ,0, 1, 1 }, // 4
+ { 1, 0, 1, 1, 0, 1, 1 }, // 5
+ { 1, 0, 1, 1, 1, 1, 1 }, // 6
+ { 1, 1, 1, 0, 0, 0, 0 }, // 7
+ { 1, 1, 1, 1, 1, 1, 1 }, // 8
+ { 1, 1, 1, 0, 0, 1, 1 }, // 9
+ { 1, 1, 1, 0, 1, 1, 1 }, // A
+ { 0, 0, 1, 1, 1, 1, 1 }, // b
+ { 1, 0, 0, 1, 1, 1, 0 }, // C
+ { 0, 1, 1, 1, 1, 0, 1 }, // d
+ { 1, 0, 0, 1, 1, 1, 1 }, // E
+ { 1, 0, 0, 0, 1, 1, 1 } }; // F
+
+Item* ECBCDTo7Segment::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECBCDTo7Segment( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ECBCDTo7Segment::libraryItem()
+{
+ return new LibraryItem(
+ QString::QString("ec/bcd_to_seven_segment"),
+ i18n("BCD to 7 Segment"),
+ i18n("Integrated Circuits"),
+ "ic2.png",
+ LibraryItem::lit_component,
+ ECBCDTo7Segment::construct
+ );
+}
+
+ECBCDTo7Segment::ECBCDTo7Segment( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, (id) ? id : "bcd_to_seven_segment" )
+{
+ m_name = i18n("BCD to Seven Segment");
+ m_desc = i18n("Converts a binary-coded-input to a form displayable by a seven segment display.<br><br>"
+ "Normal operation: <i>lt</i> (Lamp Test) and the <i>rb</i> (Ripple Blanking) are held high, <i>en</i> (Enable) is held low.");
+
+ ALogic = BLogic = CLogic = DLogic = 0L;
+ ltLogic = rbLogic = enLogic = 0L;
+
+ for ( int i=0; i<7; i++ )
+ {
+ outLogic[i] = 0L;
+ oldOut[i] = false;
+ }
+
+ QStringList pins = QStringList::split( ',', "A,B,C,D,,lt,rb,en,d,e,f,g,,a,b,c", true );
+ initDIPSymbol( pins, 48 );
+ initDIP(pins);
+
+ ALogic = createLogicIn( ecNodeWithID("A") );
+ BLogic = createLogicIn( ecNodeWithID("B") );
+ CLogic = createLogicIn( ecNodeWithID("C") );
+ DLogic = createLogicIn( ecNodeWithID("D") );
+ ltLogic = createLogicIn( ecNodeWithID("lt") );
+ rbLogic = createLogicIn( ecNodeWithID("rb") );
+ enLogic = createLogicIn( ecNodeWithID("en") );
+
+ ALogic->setCallback( this, (CallbackPtr)(&ECBCDTo7Segment::inStateChanged) );
+ BLogic->setCallback( this, (CallbackPtr)(&ECBCDTo7Segment::inStateChanged) );
+ CLogic->setCallback( this, (CallbackPtr)(&ECBCDTo7Segment::inStateChanged) );
+ DLogic->setCallback( this, (CallbackPtr)(&ECBCDTo7Segment::inStateChanged) );
+ ltLogic->setCallback( this, (CallbackPtr)(&ECBCDTo7Segment::inStateChanged) );
+ rbLogic->setCallback( this, (CallbackPtr)(&ECBCDTo7Segment::inStateChanged) );
+ enLogic->setCallback( this, (CallbackPtr)(&ECBCDTo7Segment::inStateChanged) );
+
+ for ( uint i=0; i<7; ++i )
+ {
+ outLogic[i] = createLogicOut( ecNodeWithID( QChar('a'+i) ), false );
+ outLogic[i]->setCallback( this, (CallbackPtr)(&ECBCDTo7Segment::inStateChanged) );
+ }
+ inStateChanged(false);
+}
+
+ECBCDTo7Segment::~ECBCDTo7Segment()
+{
+}
+
+void ECBCDTo7Segment::inStateChanged(bool)
+{
+ bool A = ALogic->isHigh();
+ bool B = BLogic->isHigh();
+ bool C = CLogic->isHigh();
+ bool D = DLogic->isHigh();
+ bool lt = ltLogic->isHigh(); // Lamp test
+ bool rb = rbLogic->isHigh(); // Ripple Blank
+ bool en = enLogic->isHigh(); // Enable (store)
+
+ int n = A + 2*B + 4*C + 8*D;
+// if ( n > 9 ) n = 0;
+
+ bool out[7];
+
+ if (lt) // Lamp test
+ {
+ if (rb) // Ripple blanking
+ {
+ if (en) // Enable (store)
+ {
+ for ( int i=0; i<7; i++ )
+ {
+ out[i] = oldOut[i];
+ }
+ }
+ else
+ {
+ for ( int i=0; i<7; i++ )
+ {
+ out[i] = numbers[n][i];
+ oldOut[i] = out[i];
+ }
+ }
+ }
+ else
+ {
+ for ( int i=0; i<7; i++ )
+ {
+ out[i] = false;
+ }
+ }
+ }
+ else
+ {
+ for ( int i=0; i<7; i++ )
+ {
+ out[i] = true;
+ }
+ }
+
+ for ( int i=0; i<7; i++ )
+ {
+ outLogic[i]->setHigh( out[i] );
+ }
+}
diff --git a/src/electronics/components/ecbcdto7segment.h b/src/electronics/components/ecbcdto7segment.h
new file mode 100644
index 0000000..03d4c2b
--- /dev/null
+++ b/src/electronics/components/ecbcdto7segment.h
@@ -0,0 +1,41 @@
+/***************************************************************************
+ * Copyright (C) 2003-2004 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef ECBCDTO7SEGMENT_H
+#define ECBCDTO7SEGMENT_H
+
+#include "component.h"
+#include "logic.h"
+
+/**
+@short Converts a BCD input to 7-Segment Output
+@author David Saxton
+*/
+class ECBCDTo7Segment : public CallbackClass, public Component
+{
+public:
+ ECBCDTo7Segment( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECBCDTo7Segment();
+
+ virtual bool canFlip() const { return true; }
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+private:
+ void inStateChanged( bool newState );
+ LogicIn *ALogic, *BLogic, *CLogic, *DLogic;
+ LogicIn *ltLogic, *rbLogic, *enLogic;
+ LogicOut *outLogic[7];
+
+ // Old values
+ bool oldOut[7];
+};
+
+#endif
diff --git a/src/electronics/components/ecbjt.cpp b/src/electronics/components/ecbjt.cpp
new file mode 100644
index 0000000..b4b59f2
--- /dev/null
+++ b/src/electronics/components/ecbjt.cpp
@@ -0,0 +1,153 @@
+/***************************************************************************
+ * Copyright (C) 2003-2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "bjt.h"
+#include "ecbjt.h"
+#include "ecnode.h"
+#include "libraryitem.h"
+
+#include <kiconloader.h>
+#include <klocale.h>
+#include <qpainter.h>
+
+Item * ECBJT::constructNPN( ItemDocument * itemDocument, bool newItem, const char * id )
+{
+ return new ECBJT( true, (ICNDocument*)itemDocument, newItem, id );
+}
+
+
+Item * ECBJT::constructPNP( ItemDocument * itemDocument, bool newItem, const char * id )
+{
+ return new ECBJT( false, (ICNDocument*)itemDocument, newItem, id );
+}
+
+
+LibraryItem* ECBJT::libraryItemNPN()
+{
+ return new LibraryItem(
+ "ec/npnbjt",
+ i18n("NPN"),
+ i18n("Discrete"),
+ "npn.png",
+ LibraryItem::lit_component,
+ ECBJT::constructNPN );
+}
+
+
+LibraryItem* ECBJT::libraryItemPNP()
+{
+ return new LibraryItem(
+ "ec/pnpbjt",
+ i18n("PNP"),
+ i18n("Discrete"),
+ "pnp.png",
+ LibraryItem::lit_component,
+ ECBJT::constructPNP );
+}
+
+
+ECBJT::ECBJT( bool isNPN, ICNDocument * icnDocument, bool newItem, const char * id )
+ : Component( icnDocument, newItem, id ? id : (isNPN ? "npnbjt" : "pnpbjt") )
+{
+ m_bIsNPN = isNPN;
+ if ( m_bIsNPN )
+ m_name = i18n("NPN Transistor");
+ else
+ m_name = i18n("PNP Transistor");
+
+ setSize( -8, -8, 16, 16 );
+ m_pBJT = createBJT( createPin( 8, -16, 90, "c" ), createPin( -16, 0, 0, "b" ), createPin( 8, 16, 270, "e" ), m_bIsNPN );
+
+ BJTSettings s; // will be created with the default settings
+
+ Variant * v = createProperty( "I_S", Variant::Type::Double );
+ v->setCaption("Saturation Current");
+ v->setUnit("A");
+ v->setMinValue(1e-20);
+ v->setMaxValue(1e-0);
+ v->setValue( s.I_S );
+ v->setAdvanced(true);
+
+ v = createProperty( "N_F", Variant::Type::Double );
+ v->setCaption( i18n("Forward Coefficient") );
+ v->setMinValue(1e0);
+ v->setMaxValue(1e1);
+ v->setValue( s.N_F );
+ v->setAdvanced(true);
+
+ v = createProperty( "N_R", Variant::Type::Double );
+ v->setCaption( i18n("Reverse Coefficient") );
+ v->setMinValue(1e0);
+ v->setMaxValue(1e1);
+ v->setValue( s.N_R );
+ v->setAdvanced(true);
+
+ v = createProperty( "B_F", Variant::Type::Double );
+ v->setCaption( i18n("Forward Beta") );
+ v->setMinValue(1e-1);
+ v->setMaxValue(1e3);
+ v->setValue( s.B_F );
+ v->setAdvanced(true);
+
+ v = createProperty( "B_R", Variant::Type::Double );
+ v->setCaption( i18n("Reverse Beta") );
+ v->setMinValue(1e-1);
+ v->setMaxValue(1e3);
+ v->setValue( s.B_R );
+ v->setAdvanced(true);
+}
+
+ECBJT::~ECBJT()
+{
+}
+
+
+void ECBJT::dataChanged()
+{
+ BJTSettings s;
+ s.I_S = dataDouble( "I_S" );
+ s.N_F = dataDouble( "N_F" );
+ s.N_R = dataDouble( "N_R" );
+ s.B_F = dataDouble( "B_F" );
+ s.B_R = dataDouble( "B_R" );
+
+ m_pBJT->setBJTSettings( s );
+}
+
+
+void ECBJT::drawShape( QPainter &p )
+{
+ const int _x = int(x());
+ const int _y = int(y());
+
+ initPainter(p);
+
+ p.drawLine( _x-8, _y-8, _x-8, _y+8 );
+ p.drawLine( _x+8, _y-8, _x-8, _y );
+ p.drawLine( _x+8, _y+8, _x-8, _y );
+
+ QPointArray pa(3);
+ if ( m_bIsNPN )
+ {
+ pa[0] = QPoint( _x+6, _y+7 );
+ pa[1] = QPoint( _x+2, _y+8 );
+ pa[2] = QPoint( _x+6, _y+3 );
+ }
+ else
+ {
+ pa[0] = QPoint( _x-7, _y+1 );
+ pa[1] = QPoint( _x-4, _y+5 );
+ pa[2] = QPoint( _x-2, _y );
+ }
+ p.setBrush( p.pen().color() );
+ p.drawPolygon(pa);
+
+ deinitPainter(p);
+}
diff --git a/src/electronics/components/ecbjt.h b/src/electronics/components/ecbjt.h
new file mode 100644
index 0000000..17a63e9
--- /dev/null
+++ b/src/electronics/components/ecbjt.h
@@ -0,0 +1,42 @@
+/***************************************************************************
+ * Copyright (C) 2003-2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef ECBJT_H
+#define ECBJT_H
+
+#include "component.h"
+
+class BJT;
+
+/**
+@short Simulates a BJT
+@author David Saxton
+*/
+class ECBJT : public Component
+{
+ public:
+ ECBJT( bool isNPN, ICNDocument *icnDocument, bool newItem, const char * id = 0L );
+ ~ECBJT();
+ virtual bool canFlip() const { return true; }
+
+ static Item * constructNPN( ItemDocument * itemDocument, bool newItem, const char * id );
+ static Item * constructPNP( ItemDocument * itemDocument, bool newItem, const char * id );
+ static LibraryItem * libraryItemNPN();
+ static LibraryItem * libraryItemPNP();
+
+ protected:
+ virtual void dataChanged();
+ virtual void drawShape( QPainter &p );
+
+ bool m_bIsNPN;
+ BJT * m_pBJT;
+};
+
+#endif
diff --git a/src/electronics/components/eccapacitor.cpp b/src/electronics/components/eccapacitor.cpp
new file mode 100644
index 0000000..76a09b0
--- /dev/null
+++ b/src/electronics/components/eccapacitor.cpp
@@ -0,0 +1,92 @@
+/***************************************************************************
+ * Copyright (C) 2003 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "capacitance.h"
+#include "eccapacitor.h"
+#include "ecnode.h"
+#include "libraryitem.h"
+
+#include <klocale.h>
+#include <qpainter.h>
+
+Item* ECCapacitor::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECCapacitor( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ECCapacitor::libraryItem()
+{
+ return new LibraryItem(
+ "ec/capacitor",
+ i18n("Capacitor"),
+ i18n("Discrete"),
+ "capacitor.png",
+ LibraryItem::lit_component,
+ ECCapacitor::construct
+ );
+}
+
+ECCapacitor::ECCapacitor( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, id ? id : "capacitor" )
+{
+ m_name = i18n("Capacitor");
+ m_desc = i18n("Stores electrical charge.<br><br>"
+ "The voltage across the capacitor and capacitance are related by <i>Charge = Capacitance x Voltage</i>.");
+ setSize( -8, -8, 16, 16 );
+
+ init1PinLeft();
+ init1PinRight();
+
+ m_capacitance = createCapacitance( m_pNNode[0], m_pPNode[0], 0.001 );
+
+ createProperty( "Capacitance", Variant::Type::Double );
+ property("Capacitance")->setCaption( i18n("Capacitance") );
+ property("Capacitance")->setUnit("F");
+ property("Capacitance")->setMinValue(1e-12);
+ property("Capacitance")->setMaxValue(1e12);
+ property("Capacitance")->setValue(1e-3);
+
+ addDisplayText( "capacitance", QRect( -8, -24, 16, 16 ), "", false );
+}
+
+ECCapacitor::~ECCapacitor()
+{
+}
+
+void ECCapacitor::dataChanged()
+{
+ double capacitance = dataDouble("Capacitance");
+
+ QString display = QString::number( capacitance / getMultiplier(capacitance), 'g', 3 ) + getNumberMag(capacitance) + "F";
+ setDisplayText( "capacitance", display );
+
+ m_capacitance->setCapacitance(capacitance);
+}
+
+void ECCapacitor::drawShape( QPainter &p )
+{
+ initPainter(p);
+
+ int _y = (int)y()-8;
+ int _x = (int)x()-8;
+
+ QPen pen;
+ pen.setWidth(1);
+ pen.setColor( p.pen().color() );
+ p.setPen(pen);
+ p.drawRect( _x, _y, 5, 16 );
+ p.drawRect( _x+11, _y, 5, 16 );
+
+
+ deinitPainter(p);
+// p.drawPolyline( areaPoints() );
+}
+
+
diff --git a/src/electronics/components/eccapacitor.h b/src/electronics/components/eccapacitor.h
new file mode 100644
index 0000000..4dd0ee6
--- /dev/null
+++ b/src/electronics/components/eccapacitor.h
@@ -0,0 +1,40 @@
+/***************************************************************************
+ * Copyright (C) 2003 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef ECCAPACITOR_H
+#define ECCAPACITOR_H
+
+#include "component.h"
+
+class Capacitance;
+class ECNode;
+
+/**
+@short Capacitor
+Simple capacitor
+@author David Saxton
+*/
+class ECCapacitor : public Component
+{
+public:
+ ECCapacitor( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECCapacitor();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+private:
+ void dataChanged();
+ virtual void drawShape( QPainter &p );
+
+ Capacitance * m_capacitance;
+};
+
+#endif
diff --git a/src/electronics/components/ecclockinput.cpp b/src/electronics/components/ecclockinput.cpp
new file mode 100644
index 0000000..7f1ec9c
--- /dev/null
+++ b/src/electronics/components/ecclockinput.cpp
@@ -0,0 +1,185 @@
+/***************************************************************************
+ * Copyright (C) 2003-2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "ecclockinput.h"
+
+#include "logic.h"
+#include "libraryitem.h"
+#include "simulator.h"
+
+#include <klocale.h>
+#include <qpainter.h>
+
+#include <cmath>
+
+static inline uint roundDouble( const double x )
+{
+ return uint(std::floor(x+0.5));
+}
+
+Item* ECClockInput::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECClockInput( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ECClockInput::libraryItem()
+{
+ return new LibraryItem(
+ QString("ec/clock_input"),
+ i18n("Clock Input"),
+ i18n("Logic"),
+ "clockinput.png",
+ LibraryItem::lit_component,
+ ECClockInput::construct );
+}
+
+ECClockInput::ECClockInput( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, (id) ? id : "clock_input" )
+{
+ m_name = i18n("Clock Input");
+ m_desc = i18n("A square-wave generator, outputing logical high/low at repeating time intervals.");
+ setSize( -16, -8, 32, 16 );
+
+ m_lastSetTime = 0;
+ m_time = 0;
+ m_high_time = 0;
+ m_low_time = 0;
+ m_period = 0;
+ m_bSetStepCallbacks = true;
+ m_pSimulator = Simulator::self();
+
+ for ( unsigned i = 0; i < 1000; i++ )
+ {
+ ComponentCallback * ccb = new ComponentCallback( this, (VoidCallbackPtr)(&ECClockInput::stepCallback) );
+ m_pComponentCallback[i] = new LinkedList<ComponentCallback>(ccb);
+ }
+
+ init1PinRight();
+ m_pOut = createLogicOut( m_pPNode[0], false );
+
+ createProperty( "low-time", Variant::Type::Double );
+ property("low-time")->setUnit("S");
+ property("low-time")->setCaption( i18n("Low Time") );
+ property("low-time")->setMinValue(1.0/LOGIC_UPDATE_RATE);
+ property("low-time")->setValue(0.5);
+
+ createProperty( "high-time", Variant::Type::Double );
+ property("high-time")->setUnit("S");
+ property("high-time")->setCaption( i18n("High Time") );
+ property("high-time")->setMinValue(1.0/LOGIC_UPDATE_RATE);
+ property("high-time")->setValue(0.5);
+
+ addDisplayText( "freq", QRect( -16, -24, 32, 14 ), "", false );
+}
+
+
+ECClockInput::~ECClockInput()
+{
+ for ( unsigned i = 0; i < 1000; i++ )
+ {
+ delete m_pComponentCallback[i]->data();
+ delete m_pComponentCallback[i];
+ }
+}
+
+
+void ECClockInput::dataChanged()
+{
+ m_high_time = roundDouble(dataDouble("high-time")*LOGIC_UPDATE_RATE);
+ m_low_time = roundDouble(dataDouble("low-time")*LOGIC_UPDATE_RATE);
+ m_period = m_low_time+m_high_time;
+
+ const double frequency = 1./(dataDouble("high-time")+dataDouble("low-time"));
+ QString display = QString::number( frequency / getMultiplier(frequency), 'g', 3 ) + getNumberMag(frequency) + "Hz";
+ setDisplayText( "freq", display );
+
+ bool setStepCallbacks = m_period > 100;
+ if ( setStepCallbacks != m_bSetStepCallbacks )
+ {
+ m_bSetStepCallbacks = setStepCallbacks;
+ if (setStepCallbacks)
+ m_pSimulator->detachComponentCallbacks(this);
+ else
+ m_pSimulator->attachComponentCallback( this, (VoidCallbackPtr)(&ECClockInput::stepLogic) );
+ }
+
+ m_bLastStepCallbackOut = false;
+ m_lastSetTime = m_pSimulator->time();
+}
+
+
+void ECClockInput::stepLogic()
+{
+ m_pOut->setHigh( m_time>m_low_time );
+
+ if ( ++m_time > m_period ) {
+ m_time -= int(m_time/m_period)*m_period;
+ }
+}
+
+
+void ECClockInput::stepCallback()
+{
+ m_pOut->setHigh(m_bLastStepCallbackOut);
+ m_bLastStepCallbackOut = !m_bLastStepCallbackOut;
+}
+
+
+void ECClockInput::stepNonLogic()
+{
+ if (!m_bSetStepCallbacks)
+ return;
+
+ bool addingHigh = !m_bLastStepCallbackOut;
+
+ //TODO 100 number shouldn't be hard-coded
+ long long lowerTime = m_pSimulator->time();
+ long long upperTime = lowerTime + 100;
+
+ long long upTo = m_lastSetTime;
+
+ while ( upTo + (addingHigh?m_high_time:m_low_time) < upperTime )
+ {
+ upTo += addingHigh ? m_high_time : m_low_time;
+ addingHigh = !addingHigh;
+
+ long long at = upTo-lowerTime;
+ if ( at >= 0 && at < 100 )
+ m_pSimulator->addStepCallback( at, m_pComponentCallback[at] );
+ }
+
+ m_lastSetTime = upTo;
+}
+
+
+void ECClockInput::drawShape( QPainter &p )
+{
+ initPainter(p);
+
+ int _x = (int)x()-10;
+ int _y = (int)y()-8;
+
+ p.drawRect( _x-6, _y, 32, 16 );
+
+ p.drawLine( _x, _y+8, _x, _y+4 );
+ p.drawLine( _x, _y+4, _x+4, _y+4 );
+ p.drawLine( _x+4, _y+4, _x+4, _y+12 );
+ p.drawLine( _x+4, _y+12, _x+8, _y+12 );
+ p.drawLine( _x+8, _y+12, _x+8, _y+4 );
+ p.drawLine( _x+8, _y+4, _x+12, _y+4 );
+ p.drawLine( _x+12, _y+4, _x+12, _y+12 );
+ p.drawLine( _x+12, _y+12, _x+16, _y+12 );
+ p.drawLine( _x+16, _y+12, _x+16, _y+4 );
+ p.drawLine( _x+16, _y+4, _x+20, _y+4 );
+ p.drawLine( _x+20, _y+4, _x+20, _y+8 );
+
+ deinitPainter(p);
+}
+
diff --git a/src/electronics/components/ecclockinput.h b/src/electronics/components/ecclockinput.h
new file mode 100644
index 0000000..c7f7d14
--- /dev/null
+++ b/src/electronics/components/ecclockinput.h
@@ -0,0 +1,56 @@
+/***************************************************************************
+ * Copyright (C) 2003-2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef ECCLOCKINPUT_H
+#define ECCLOCKINPUT_H
+
+#include "component.h"
+
+class ComponentCallback;
+class Simulator;
+
+template <typename T>
+class LinkedList;
+
+/**
+@short Boolean clock input
+@author David Saxton
+*/
+class ECClockInput : public Component
+{
+public:
+ ECClockInput( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECClockInput();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+ void stepCallback();
+ void stepLogic();
+ virtual void stepNonLogic();
+ virtual bool doesStepNonLogic() const { return true; }
+
+protected:
+ virtual void drawShape( QPainter &p );
+ void dataChanged();
+
+ uint m_time;
+ uint m_high_time;
+ uint m_low_time;
+ uint m_period;
+ long long m_lastSetTime;
+ LogicOut * m_pOut;
+ bool m_bSetStepCallbacks;
+ bool m_bLastStepCallbackOut;
+ Simulator * m_pSimulator;
+ LinkedList<ComponentCallback> * m_pComponentCallback[1000];
+};
+
+#endif
diff --git a/src/electronics/components/eccurrentsignal.cpp b/src/electronics/components/eccurrentsignal.cpp
new file mode 100644
index 0000000..e6dc351
--- /dev/null
+++ b/src/electronics/components/eccurrentsignal.cpp
@@ -0,0 +1,92 @@
+/***************************************************************************
+ * Copyright (C) 2003-2004 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "currentsignal.h"
+#include "eccurrentsignal.h"
+#include "ecnode.h"
+#include "libraryitem.h"
+#include "pin.h"
+#include "simulator.h"
+
+#include <klocale.h>
+#include <qpainter.h>
+
+Item* ECCurrentSignal::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECCurrentSignal( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ECCurrentSignal::libraryItem()
+{
+ return new LibraryItem(
+ QString("ec/ac_current"),
+ i18n("Current Signal"),
+ i18n("Sources"),
+ "currentsignal.png",
+ LibraryItem::lit_component,
+ ECCurrentSignal::construct );
+}
+
+ECCurrentSignal::ECCurrentSignal( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, (id) ? id : "current_signal" )
+{
+ m_name = i18n("Current Signal");
+ m_desc = i18n("Provides a variety of current signals");
+ setSize( -8, -8, 16, 16 );
+
+ init1PinLeft();
+ init1PinRight();
+
+ m_pNNode[0]->pin()->setGroundType( Pin::gt_low );
+ m_currentSignal = createCurrentSignal( m_pNNode[0], m_pPNode[0], 0. );
+ m_currentSignal->setStep( 1./LINEAR_UPDATE_RATE, ElementSignal::st_sinusoidal, 50. );
+
+ createProperty( "1-frequency", Variant::Type::Double );
+ property("1-frequency")->setCaption( i18n("Frequency") );
+ property("1-frequency")->setUnit("Hz");
+ property("1-frequency")->setMinValue(1e-9);
+ property("1-frequency")->setMaxValue(1e3);
+ property("1-frequency")->setValue(50.0);
+
+ createProperty( "1-current", Variant::Type::Double );
+ property("1-current")->setCaption( i18n("Current Range") );
+ property("1-current")->setUnit("A");
+ property("1-current")->setMinValue(-1e12);
+ property("1-current")->setMaxValue(1e12);
+ property("1-current")->setValue(0.02);
+
+ addDisplayText( "~", QRect( -8, -8, 16, 16 ), "~" );
+ addDisplayText( "current", QRect( -16, -24, 32, 16 ), "" );
+}
+
+
+ECCurrentSignal::~ECCurrentSignal()
+{
+}
+
+void ECCurrentSignal::dataChanged()
+{
+ const double current = dataDouble("1-current");
+ const double frequency = dataDouble("1-frequency");
+
+ QString display = QString::number( current / getMultiplier(current), 'g', 3 ) + getNumberMag(current) + "A";
+ setDisplayText( "current", display );
+
+ m_currentSignal->setStep( 1./LINEAR_UPDATE_RATE, ElementSignal::st_sinusoidal, frequency );
+ m_currentSignal->setCurrent(current);
+}
+
+void ECCurrentSignal::drawShape( QPainter &p )
+{
+ initPainter(p);
+ p.drawEllipse( (int)x()-8, (int)y()-8, width(), height() );
+ deinitPainter(p);
+}
+
diff --git a/src/electronics/components/eccurrentsignal.h b/src/electronics/components/eccurrentsignal.h
new file mode 100644
index 0000000..88dd276
--- /dev/null
+++ b/src/electronics/components/eccurrentsignal.h
@@ -0,0 +1,36 @@
+/***************************************************************************
+ * Copyright (C) 2003-2004 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef ECCURRENTSIGNAL_H
+#define ECCURRENTSIGNAL_H
+
+#include "component.h"
+
+/**
+@short Provides a current signal (sinusoidal, square, etc)
+@author David Saxton
+*/
+class ECCurrentSignal : public Component
+{
+public:
+ ECCurrentSignal( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECCurrentSignal();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+protected:
+ virtual void drawShape( QPainter &p );
+ void dataChanged();
+
+ CurrentSignal *m_currentSignal;
+};
+
+#endif
diff --git a/src/electronics/components/eccurrentsource.cpp b/src/electronics/components/eccurrentsource.cpp
new file mode 100644
index 0000000..76ecf3e
--- /dev/null
+++ b/src/electronics/components/eccurrentsource.cpp
@@ -0,0 +1,94 @@
+/***************************************************************************
+ * Copyright (C) 2003 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+
+#include "currentsource.h"
+#include "eccurrentsource.h"
+#include "ecnode.h"
+#include "libraryitem.h"
+#include "pin.h"
+
+#include <klocale.h>
+#include <qpainter.h>
+
+Item* ECCurrentSource::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECCurrentSource( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ECCurrentSource::libraryItem()
+{
+ return new LibraryItem(
+ QString::QString("ec/current_source"),
+ i18n("Current Source"),
+ i18n("Sources"),
+ "current_source.png",
+ LibraryItem::lit_component,
+ ECCurrentSource::construct );
+}
+
+ECCurrentSource::ECCurrentSource( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, (id) ? id : "current_source" )
+{
+ m_name = i18n("Current Source");
+ m_desc = i18n("Provides a fixed current source.");
+ setSize( -16, -8, 24, 24 );
+
+ init1PinLeft(8);
+ init1PinRight(8);
+ m_pNNode[0]->pin()->setGroundType( Pin::gt_low );
+
+ m_currentSource = createCurrentSource( m_pNNode[0], m_pPNode[0], 0. );
+
+ createProperty( "current", Variant::Type::Double );
+ property("current")->setCaption( i18n("Current") );
+ property("current")->setUnit("A");
+ property("current")->setMinValue(-1e12);
+ property("current")->setMaxValue(1e12);
+ property("current")->setValue(0.02);
+
+ addDisplayText("current", QRect( -16, -16, 24, 0 ), "" );
+}
+
+
+ECCurrentSource::~ECCurrentSource()
+{
+}
+
+void ECCurrentSource::dataChanged()
+{
+ double current = dataDouble("current");
+ m_currentSource->setCurrent(current);
+
+ QString display = QString::number( current / getMultiplier(current), 'g', 3 ) + getNumberMag(current) + "A";
+ setDisplayText("current", display );
+}
+
+void ECCurrentSource::drawShape( QPainter &p )
+{
+ initPainter(p);
+
+ int _x = (int)x()-16;
+ int _y = (int)y()-24;
+
+ // Top arrow indicating current direction
+ p.drawLine( _x+width(), _y+19, _x, _y+19 );
+ p.drawLine( _x+width(), _y+19, _x+width()-3, _y+16 );
+ p.drawLine( _x+width(), _y+19, _x+width()-3, _y+22 );
+
+ // Double circules
+ p.drawEllipse( _x, _y+24, 16, 16 );
+ p.drawEllipse( _x+8, _y+24, 16, 16 );
+
+ deinitPainter(p);
+}
+
+
+
diff --git a/src/electronics/components/eccurrentsource.h b/src/electronics/components/eccurrentsource.h
new file mode 100644
index 0000000..6332eba
--- /dev/null
+++ b/src/electronics/components/eccurrentsource.h
@@ -0,0 +1,36 @@
+/***************************************************************************
+ * Copyright (C) 2003 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef ECCURRENTSOURCE_H
+#define ECCURRENTSOURCE_H
+
+#include "component.h"
+
+/**
+@short Fixed current source
+@author David Saxton
+*/
+class ECCurrentSource : public Component
+{
+public:
+ ECCurrentSource( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECCurrentSource();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+private:
+ virtual void drawShape( QPainter &p );
+ void dataChanged();
+
+ CurrentSource *m_currentSource;
+};
+
+#endif
diff --git a/src/electronics/components/ecdiode.cpp b/src/electronics/components/ecdiode.cpp
new file mode 100644
index 0000000..1d63bce
--- /dev/null
+++ b/src/electronics/components/ecdiode.cpp
@@ -0,0 +1,120 @@
+/***************************************************************************
+ * Copyright (C) 2003,2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "diode.h"
+#include "ecdiode.h"
+#include "ecnode.h"
+#include "libraryitem.h"
+
+#include <klocale.h>
+#include <qpainter.h>
+
+Item* ECDiode::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECDiode( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ECDiode::libraryItem()
+{
+ return new LibraryItem(
+ "ec/diode",
+ i18n("Diode"),
+ i18n("Discrete"),
+ "diode.png",
+ LibraryItem::lit_component,
+ ECDiode::construct );
+}
+
+ECDiode::ECDiode( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, id ? id : "diode" )
+{
+ m_name = i18n("Diode");
+ m_desc = i18n("Allows current to flow in the direction indicated by the arrow when a certain voltage difference has been reached.");
+
+ setSize( -8, -8, 16, 16 );
+
+ init1PinLeft();
+ init1PinRight();
+
+ m_diode = createDiode( m_pNNode[0], m_pPNode[0] );
+
+ DiodeSettings ds; // it will have the default properties that we use
+
+ createProperty( "I_S", Variant::Type::Double );
+ property("I_S")->setCaption("Saturation Current");
+ property("I_S")->setUnit("A");
+ property("I_S")->setMinValue(1e-20);
+ property("I_S")->setMaxValue(1e-0);
+ property("I_S")->setValue( ds.I_S );
+ property("I_S")->setAdvanced(true);
+
+ createProperty( "N", Variant::Type::Double );
+ property("N")->setCaption( i18n("Emission Coefficient") );
+ property("N")->setMinValue(1e0);
+ property("N")->setMaxValue(1e1);
+ property("N")->setValue( ds.N );
+ property("N")->setAdvanced(true);
+
+ createProperty( "V_B", Variant::Type::Double );
+ property("V_B")->setCaption( i18n("Breakdown Voltage") );
+ property("V_B")->setUnit("V");
+ property("V_B")->setMinAbsValue(1e-5);
+ property("V_B")->setMaxValue(1e10);
+ property("V_B")->setValue( ds.V_B );
+ property("V_B")->setAdvanced(true);
+
+// createProperty( "R", Variant::Type::Double );
+// property("R")->setCaption( i18n("Series Resistance") );
+// property("R")->setUnit( QChar(0x3a9) );
+// property("R")->setMinValue(1e-5);
+// property("R")->setMaxValue(1e0);
+// property("R")->setValue( ds.R );
+// property("R")->setAdvanced(true);
+}
+
+
+ECDiode::~ECDiode()
+{
+}
+
+
+void ECDiode::dataChanged()
+{
+ DiodeSettings ds;
+
+ ds.I_S = dataDouble("I_S");
+ ds.V_B = dataDouble("V_B");
+ ds.N = dataDouble("N");
+// ds.R = dataDouble("R");
+
+ m_diode->setDiodeSettings( ds );
+}
+
+
+void ECDiode::drawShape( QPainter & p )
+{
+ initPainter(p);
+
+ int _x = int(x());
+ int _y = int(y());
+
+ QPointArray pa(3);
+ pa[0] = QPoint( 8, 0 );
+ pa[1] = QPoint( -8, -8 );
+ pa[2] = QPoint( -8, 8 );
+ pa.translate( _x, _y );
+ p.drawPolygon(pa);
+ p.drawPolyline(pa);
+
+ p.drawLine( _x+8, _y-8, _x+8, _y+8 );
+
+ deinitPainter(p);
+}
+
diff --git a/src/electronics/components/ecdiode.h b/src/electronics/components/ecdiode.h
new file mode 100644
index 0000000..fa8d034
--- /dev/null
+++ b/src/electronics/components/ecdiode.h
@@ -0,0 +1,35 @@
+/***************************************************************************
+ * Copyright (C) 2003,2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef ECDIODE_H
+#define ECDIODE_H
+
+#include "component.h"
+
+/**
+@short Simple diode
+@author David Saxton
+*/
+class ECDiode : public Component
+{
+public:
+ ECDiode( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECDiode();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+protected:
+ void drawShape( QPainter & p );
+ void dataChanged();
+ Diode *m_diode;
+};
+
+#endif
diff --git a/src/electronics/components/ecfixedvoltage.cpp b/src/electronics/components/ecfixedvoltage.cpp
new file mode 100644
index 0000000..06eb707
--- /dev/null
+++ b/src/electronics/components/ecfixedvoltage.cpp
@@ -0,0 +1,77 @@
+/***************************************************************************
+ * Copyright (C) 2003-2004 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "ecfixedvoltage.h"
+
+#include "ecnode.h"
+#include "voltagepoint.h"
+#include "libraryitem.h"
+
+#include <klocale.h>
+#include <qpainter.h>
+
+Item* ECFixedVoltage::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECFixedVoltage( (ICNDocument*)itemDocument, newItem, id );
+}
+LibraryItem* ECFixedVoltage::libraryItem()
+{
+ return new LibraryItem(
+ "ec/fixed_voltage",
+ i18n("Fixed Voltage"),
+ i18n("Sources"),
+ "voltage.png",
+ LibraryItem::lit_component,
+ ECFixedVoltage::construct );
+}
+
+ECFixedVoltage::ECFixedVoltage( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, id ? id : "fixed_voltage" )
+{
+ m_name = i18n("Fixed Voltage");
+ m_desc = i18n("Provides a fixed voltage point to connect components to.");
+ setSize( -8, -8, 16, 16 );
+
+ init1PinRight();
+ m_voltagePoint = createVoltagePoint( m_pPNode[0], 5.0 );
+
+ addDisplayText( "voltage", QRect( -24, -20, width()+32, 12 ), "" );
+
+ createProperty( "voltage", Variant::Type::Double );
+ property("voltage")->setUnit("V");
+ property("voltage")->setCaption( i18n("Voltage") );
+ property("voltage")->setMinValue(-1e15);
+ property("voltage")->setMaxValue(1e15);
+ property("voltage")->setValue(5.0);
+}
+
+ECFixedVoltage::~ECFixedVoltage()
+{
+}
+
+void ECFixedVoltage::dataChanged()
+{
+ const double voltage = dataDouble("voltage");
+ QString display = QString::number( voltage / getMultiplier(voltage), 'g', 3 ) + getNumberMag(voltage) + "V";
+ setDisplayText( "voltage", display );
+ m_voltagePoint->setVoltage(voltage);
+}
+
+void ECFixedVoltage::drawShape( QPainter &p )
+{
+ initPainter(p);
+ int _x = int(x());
+ int _y = int(y());
+ p.drawEllipse( _x-4, _y-4, 8, 8 );
+ p.setPen( m_pPNode[0]->isSelected() ? m_selectedCol : Qt::black );
+ p.drawLine( _x+4, _y, _x+8, _y );
+ deinitPainter(p);
+}
+
diff --git a/src/electronics/components/ecfixedvoltage.h b/src/electronics/components/ecfixedvoltage.h
new file mode 100644
index 0000000..ba20358
--- /dev/null
+++ b/src/electronics/components/ecfixedvoltage.h
@@ -0,0 +1,35 @@
+/***************************************************************************
+ * Copyright (C) 2003-2004 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef ECFIXEDVOLTAGE_H
+#define ECFIXEDVOLTAGE_H
+
+#include "component.h"
+
+/**
+@short Fixed voltage source
+@author David Saxton
+*/
+class ECFixedVoltage : public Component
+{
+public:
+ ECFixedVoltage( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECFixedVoltage();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+private:
+ virtual void drawShape( QPainter &p );
+ void dataChanged();
+ VoltagePoint *m_voltagePoint;
+};
+
+#endif
diff --git a/src/electronics/components/ecground.cpp b/src/electronics/components/ecground.cpp
new file mode 100644
index 0000000..efbfc41
--- /dev/null
+++ b/src/electronics/components/ecground.cpp
@@ -0,0 +1,66 @@
+/***************************************************************************
+ * Copyright (C) 2003-2004 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "ecground.h"
+
+#include "ecnode.h"
+#include "libraryitem.h"
+#include "pin.h"
+
+#include <klocale.h>
+#include <qpainter.h>
+
+Item* ECGround::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECGround( (ICNDocument*)itemDocument, newItem, id );
+}
+LibraryItem* ECGround::libraryItem()
+{
+ return new LibraryItem(
+ QString::QString("ec/ground"),
+ i18n("Ground (0V)"),
+ i18n("Sources"),
+ "ground.png",
+ LibraryItem::lit_component,
+ ECGround::construct );
+}
+
+ECGround::ECGround( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, (id) ? id : "ground" )
+{
+ m_name = i18n("Ground");
+ m_desc = i18n("Ground (0V) point");
+ setSize( -8, -8, 16, 16 );
+ init1PinRight();
+ m_pPNode[0]->pin()->setGroundType( Pin::gt_always );
+ setAngleDegrees(270);
+}
+
+ECGround::~ECGround()
+{
+}
+
+void ECGround::drawShape( QPainter &p )
+{
+ initPainter(p);
+ int _x = (int)x()-8;
+ int _y = (int)y()-8;
+ QPen pen;
+ pen.setWidth(2);
+ pen.setColor( p.pen().color() );
+ p.setPen(pen);
+ p.drawLine( _x+15, _y, _x+15, _y+16 );
+ p.drawLine( _x+10, _y+3, _x+10, _y+13 );
+ p.drawLine( _x+5, _y+6, _x+5, _y+10 );
+ deinitPainter(p);
+}
+
+
+
diff --git a/src/electronics/components/ecground.h b/src/electronics/components/ecground.h
new file mode 100644
index 0000000..0cf97bc
--- /dev/null
+++ b/src/electronics/components/ecground.h
@@ -0,0 +1,33 @@
+/***************************************************************************
+ * Copyright (C) 2003-2004 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef ECGROUND_H
+#define ECGROUND_H
+
+#include "component.h"
+
+/**
+@short Fixed voltage source
+@author David Saxton
+*/
+class ECGround : public Component
+{
+public:
+ ECGround( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECGround();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+private:
+ virtual void drawShape( QPainter &p );
+};
+
+#endif
diff --git a/src/electronics/components/eckeypad.cpp b/src/electronics/components/eckeypad.cpp
new file mode 100644
index 0000000..89d2659
--- /dev/null
+++ b/src/electronics/components/eckeypad.cpp
@@ -0,0 +1,199 @@
+/***************************************************************************
+ * Copyright (C) 2003,2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "canvasitemparts.h"
+#include "eckeypad.h"
+#include "libraryitem.h"
+#include "switch.h"
+
+#include "ecnode.h"
+#include <klocale.h>
+
+Item* ECKeyPad::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECKeyPad( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ECKeyPad::libraryItem()
+{
+ return new LibraryItem(
+ QString("ec/keypad"),
+ i18n("Keypad"),
+ i18n("Switches"),
+ "keypad.png",
+ LibraryItem::lit_component,
+ ECKeyPad::construct );
+}
+
+const QString text[4][9] =
+ { { "1","2","3","A","E","I","M","Q","U" },
+ { "4","5","6","B","F","J","N","R","V" },
+ { "7","8","9","C","G","K","O","S","W" },
+ { "*","0","#","D","H","L","P","T","X" } };
+
+ECKeyPad::ECKeyPad( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, (id) ? id : "keypad" )
+{
+ m_name = i18n("Keypad");
+ m_desc = i18n("Provides a numeric array of Push-to-Make switches, with 4 rows and a configurable number of columns.");
+
+ createProperty( "useToggles", Variant::Type::Bool );
+ property("useToggles")->setCaption( i18n("Use Toggles") );
+ property("useToggles")->setValue(false);
+
+ createProperty( "numCols", Variant::Type::Int );
+ property("numCols")->setCaption( i18n("Columns") );
+ property("numCols")->setMinValue(3);
+ property("numCols")->setMaxValue(9);
+ property("numCols")->setValue(3);
+
+ Variant * v = createProperty( "bounce", Variant::Type::Bool );
+ v->setCaption("Bounce");
+ v->setAdvanced(true);
+ v->setValue(false);
+
+ v = createProperty( "bounce_period", Variant::Type::Double );
+ v->setCaption("Bounce Period");
+ v->setAdvanced(true);
+ v->setUnit("s");
+ v->setValue(5e-3);
+
+ for ( int i = 0; i < 4; i++ )
+ createPin( 0, -32+i*24, 0, QString("row_%1").arg(QString::number(i)) );
+
+ m_numCols = 0;
+}
+
+
+ECKeyPad::~ECKeyPad()
+{
+}
+
+
+QString ECKeyPad::buttonID( int row, int col ) const
+{
+ return QString("b_%1_%2").arg(QString::number(row)).arg(QString::number(col));
+}
+
+
+int ECKeyPad::sideLength( unsigned numButtons ) const
+{
+ return 8 + 24*numButtons;
+}
+
+
+void ECKeyPad::dataChanged()
+{
+ initPins( dataInt("numCols") );
+
+ bool useToggle = dataBool("useToggles");
+ bool bounce = dataBool("bounce");
+ int bouncePeriod_ms = int(dataDouble("bounce_period")*1e3);
+
+ for ( unsigned i = 0; i < 4; i++ )
+ {
+ for ( unsigned j = 0; j < m_numCols; j++ )
+ {
+ button( buttonID(i,j) )->setToggle(useToggle);
+ m_switch[i][j]->setBounce( bounce, bouncePeriod_ms );
+ }
+ }
+}
+
+
+void ECKeyPad::initPins( unsigned numCols )
+{
+ if ( numCols < 3 )
+ numCols = 3;
+ else if ( numCols > 9 )
+ numCols = 9;
+
+ if ( numCols == m_numCols )
+ return;
+
+ int w = sideLength(numCols);
+ int h = sideLength(4);
+ setSize( -int(w/16)*8, -int(h/16)*8, w, h, true );
+
+ if ( numCols > m_numCols )
+ {
+ // Adding columns
+
+ for ( unsigned i = 0; i < 4; i++ )
+ {
+ for ( unsigned j = m_numCols; j < numCols; j++ )
+ addButton( buttonID(i,j), QRect( 0, 0, 20, 20 ), text[i][j] );
+ }
+
+ ECNode * cols[numCols];
+
+ for ( unsigned j = m_numCols; j < numCols; j++ )
+ cols[j] = createPin( 0, 64, 270, "col_" + QString::number(j) );
+
+ for ( unsigned i = 0; i < 4; i++ )
+ {
+ ECNode * row = ecNodeWithID("row_"+QString::number(i));
+ for ( unsigned j = m_numCols; j < numCols; j++ )
+ m_switch[i][j] = createSwitch( cols[j], row, true );
+ }
+ }
+ else
+ {
+ // Remove columns
+
+ for ( unsigned i = 0; i < 4; i++ )
+ {
+ for ( unsigned j = numCols; j < m_numCols; j++ )
+ removeWidget( buttonID(i,j) );
+ }
+
+ for ( unsigned j = numCols; j < m_numCols; j++ )
+ removeNode( "col_" + QString::number(j) );
+
+ for ( unsigned i = 0; i < 4; i++ )
+ {
+ for ( unsigned j = m_numCols; j < numCols; j++ )
+ removeSwitch( m_switch[i][j] );
+ }
+ }
+
+ //BEGIN Update Positions
+ m_numCols = numCols;
+
+ for ( int i = 0; i < 4; i++ )
+ {
+ for ( int j = 0; j < int(m_numCols); j++ )
+ {
+ widgetWithID( buttonID(i,j) )->setOriginalRect(
+ QRect( offsetX() + 6 + 24*j, offsetY() + 6 + 24*i, 20, 20 ) );
+ }
+ }
+
+ for ( int i = 0; i < 4; i++ )
+ m_nodeMap["row_" + QString::number(i)].x = width()+offsetX();
+
+ for ( int j = 0; j < int(m_numCols); j++ )
+ m_nodeMap["col_" + QString::number(j)].x = 24*j+offsetX()+16;
+
+ updateAttachedPositioning();
+ //END Update Positions
+}
+
+
+void ECKeyPad::buttonStateChanged( const QString &id, bool state )
+{
+ if ( !id.startsWith("b_") )
+ return;
+
+ QStringList tags = QStringList::split( '_', id );
+ const int i = tags[1].toInt();
+ const int j = tags[2].toInt();
+ m_switch[i][j]->setState( state ? Switch::Closed : Switch::Open );
+}
diff --git a/src/electronics/components/eckeypad.h b/src/electronics/components/eckeypad.h
new file mode 100644
index 0000000..18a497c
--- /dev/null
+++ b/src/electronics/components/eckeypad.h
@@ -0,0 +1,42 @@
+/***************************************************************************
+ * Copyright (C) 2003,2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef ECKEYPAD_H
+#define ECKEYPAD_H
+
+#include "component.h"
+
+/**
+@short 4x3 PTM Keypad
+@author David Saxton
+*/
+class ECKeyPad : public Component
+{
+ public:
+ ECKeyPad( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECKeyPad();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+ virtual void buttonStateChanged( const QString &id, bool state );
+ virtual bool canFlip() const { return true; }
+
+ protected:
+ virtual void dataChanged();
+ void initPins( unsigned numCols);
+ QString buttonID( int row, int col ) const;
+ int sideLength( unsigned numButtons ) const;
+
+ Switch *m_switch[4][11];
+ unsigned m_numCols;
+};
+
+#endif
diff --git a/src/electronics/components/ecled.cpp b/src/electronics/components/ecled.cpp
new file mode 100644
index 0000000..c865de6
--- /dev/null
+++ b/src/electronics/components/ecled.cpp
@@ -0,0 +1,134 @@
+/***************************************************************************
+ * Copyright (C) 2003 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "colorcombo.h"
+#include "diode.h"
+#include "ecled.h"
+#include "ecnode.h"
+#include "libraryitem.h"
+#include "simulator.h"
+
+#include <klocale.h>
+#include <qpainter.h>
+
+Item* ECLed::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECLed( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ECLed::libraryItem()
+{
+ return new LibraryItem(
+ QString::QString("ec/led"),
+ i18n("LED"),
+ i18n("Outputs"),
+ "led.png",
+ LibraryItem::lit_component,
+ ECLed::construct
+ );
+}
+
+ECLed::ECLed( ICNDocument *icnDocument, bool newItem, const char *id )
+ : ECDiode( icnDocument, newItem, (id) ? id : "led" )
+{
+ m_bDynamicContent = true;
+ m_name = i18n("LED");
+ m_desc = i18n("Light Emitting Diode");
+ setSize( -8, -16, 24, 24, true );
+ avg_brightness = 255;
+ lastUpdatePeriod = 0.;
+ r=g=b=0;
+ last_brightness = 255;
+
+ createProperty( "0-color", Variant::Type::Color );
+ property("0-color")->setCaption( i18n("Color") );
+ property("0-color")->setColorScheme( ColorCombo::LED );
+}
+
+ECLed::~ECLed()
+{
+}
+
+void ECLed::dataChanged()
+{
+ QColor color = dataColor("0-color");
+ r = color.red();
+ g = color.green();
+ b = color.blue();
+ r /= 0x100;
+ g /= 0x100;
+ b /= 0x100;
+}
+
+void ECLed::stepNonLogic()
+{
+ double interval = 1./LINEAR_UPDATE_RATE;
+ avg_brightness += brightness(m_diode->current())*interval;
+ lastUpdatePeriod += interval;
+}
+
+void ECLed::drawShape( QPainter &p )
+{
+ int _x = int(x());
+ int _y = int(y());
+
+ initPainter(p);
+
+ //BEGIN draw "Diode" part
+ uint _b;
+ if ( lastUpdatePeriod == 0. )
+ _b = last_brightness;
+ else
+ {
+ _b = (uint)(avg_brightness/lastUpdatePeriod);
+ last_brightness = _b;
+ }
+ avg_brightness = 0.;
+ lastUpdatePeriod = 0.;
+
+ p.setBrush( QColor( uint(255-(255-_b)*(1-r)), uint(255-(255-_b)*(1-g)), uint(255-(255-_b)*(1-b)) ) );
+
+ QPointArray pa(3);
+ pa[0] = QPoint( 8, 0 );
+ pa[1] = QPoint( -8, -8 );
+ pa[2] = QPoint( -8, 8 );
+ pa.translate( _x, _y );
+ p.drawPolygon(pa);
+ p.drawPolyline(pa);
+
+ p.drawLine( _x+8, _y-8, _x+8, _y+8 );
+ //END draw "Diode" part
+
+
+
+ //BEGIN draw "Arrows" part
+ p.drawLine( _x+7, _y-10, _x+10, _y-13 ); // Tail of left arrow
+ p.drawLine( _x+10, _y-13, _x+8, _y-13 ); // Left edge of left arrow tip
+ p.drawLine( _x+10, _y-13, _x+10, _y-11 ); // Right edge of left arrow tip
+
+ p.drawLine( _x+10, _y-7, _x+13, _y-10 ); // Tail of right arrow
+ p.drawLine( _x+13, _y-10, _x+11, _y-10 ); // Left edge of right arrow tip
+ p.drawLine( _x+13, _y-10, _x+13, _y-8 ); // Right edge of right arrow tip
+
+ p.drawLine( _x+8, _y-13, _x+13, _y-8 ); // Diagonal line that forms base of both arrow tips
+ //END draw "Arrows" part1
+
+
+ deinitPainter(p);
+}
+
+
+uint ECLed::brightness( double i )
+{
+ if ( i > 0.018 ) return 0;
+ if ( i < 0.002 ) return 255;
+ return (uint)(255*(1-((i-0.002)/0.016)));
+}
+
diff --git a/src/electronics/components/ecled.h b/src/electronics/components/ecled.h
new file mode 100644
index 0000000..ce24598
--- /dev/null
+++ b/src/electronics/components/ecled.h
@@ -0,0 +1,48 @@
+/***************************************************************************
+ * Copyright (C) 2003 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef ECLED_H
+#define ECLED_H
+
+#include "component.h"
+#include "ecdiode.h"
+
+/**
+@short Simulates a LED
+@author David Saxton
+*/
+class ECLed : public ECDiode
+{
+public:
+ ECLed( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECLed();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+ /**
+ * Returns the brightness for the given current, from 255 (off) -> 0 (on)
+ */
+ static uint brightness( double i );
+
+ virtual void dataChanged();
+ virtual void stepNonLogic();
+ virtual bool doesStepNonLogic() const { return true; }
+
+private:
+ virtual void drawShape( QPainter &p );
+
+ double r, g, b;
+
+ double avg_brightness;
+ uint last_brightness;
+ double lastUpdatePeriod;
+};
+
+#endif
diff --git a/src/electronics/components/ecopamp.cpp b/src/electronics/components/ecopamp.cpp
new file mode 100644
index 0000000..dbb7457
--- /dev/null
+++ b/src/electronics/components/ecopamp.cpp
@@ -0,0 +1,85 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "ecopamp.h"
+
+#include "ecnode.h"
+#include "libraryitem.h"
+
+#include <klocale.h>
+#include <qpainter.h>
+
+Item* ECOpAmp::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECOpAmp( (ICNDocument*)itemDocument, newItem, id );
+}
+
+
+LibraryItem* ECOpAmp::libraryItem()
+{
+ return new LibraryItem(
+ "ec/opamp",
+ i18n("Op Amp"),
+ i18n("Integrated Circuits"),
+ "opamp.png",
+ LibraryItem::lit_component,
+ ECOpAmp::construct );
+}
+
+
+ECOpAmp::ECOpAmp( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, id ? id : "opamp" )
+{
+ m_name = i18n("Operational Amplifier");
+ m_desc = i18n("Ideal amplifier");
+
+ QPointArray pa(3);
+ pa[0] = QPoint( -16, -16 );
+ pa[1] = QPoint( 16, 0 );
+ pa[2] = QPoint( -16, 16 );
+ setItemPoints( pa, true );
+
+ init2PinLeft( -8, 8 );
+ init1PinRight();
+ createOpAmp( m_pNNode[0], m_pPNode[0], m_pNNode[1] );
+}
+
+
+ECOpAmp::~ECOpAmp()
+{
+}
+
+
+void ECOpAmp::drawShape( QPainter & p )
+{
+ initPainter(p);
+
+ int _x = int(x());
+ int _y = int(y());
+
+ QPointArray pa(3);
+ pa[0] = QPoint( _x-16, _y-16 );
+ pa[1] = QPoint( _x+16, _y );
+ pa[2] = QPoint( _x-16, _y+16 );
+
+ p.drawPolygon(pa);
+ p.drawPolyline(pa);
+
+ // Plus symbol
+ p.drawLine( _x-9, _y-8, _x-9, _y-2 );
+ p.drawLine( _x-12, _y-5, _x-6, _y-5 );
+
+ // Minus symbol
+ p.drawLine( _x-11, _y+6, _x-7, _y+6 );
+
+ deinitPainter(p);
+}
+
+
diff --git a/src/electronics/components/ecopamp.h b/src/electronics/components/ecopamp.h
new file mode 100644
index 0000000..6b6b147
--- /dev/null
+++ b/src/electronics/components/ecopamp.h
@@ -0,0 +1,35 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef ECOPAMP_H
+#define ECOPAMP_H
+
+#include "component.h"
+
+/**
+@short Operational Amplifier
+@author David Saxton
+*/
+class ECOpAmp : public Component
+{
+ public:
+ ECOpAmp( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECOpAmp();
+
+ virtual bool canFlip() const { return true; }
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+ protected:
+ virtual void drawShape( QPainter & p );
+};
+
+#endif
diff --git a/src/electronics/components/ecpotentiometer.cpp b/src/electronics/components/ecpotentiometer.cpp
new file mode 100644
index 0000000..db0fedd
--- /dev/null
+++ b/src/electronics/components/ecpotentiometer.cpp
@@ -0,0 +1,119 @@
+/***************************************************************************
+ * Copyright (C) 2003-2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "canvasitemparts.h"
+#include "ecnode.h"
+#include "ecpotentiometer.h"
+#include "libraryitem.h"
+#include "resistance.h"
+
+#include <klocale.h>
+#include <qpainter.h>
+#include <qstyle.h>
+
+Item* ECPotentiometer::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECPotentiometer( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ECPotentiometer::libraryItem()
+{
+ return new LibraryItem(
+ "ec/potentiometer",
+ i18n("Potentiometer"),
+ i18n("Discrete"),
+ "potentiometer.png",
+ LibraryItem::lit_component,
+ ECPotentiometer::construct );
+}
+
+ECPotentiometer::ECPotentiometer( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, id ? id : "potentiometer" )
+{
+ m_name = i18n("Potentiometer");
+ m_desc =i18n("Consists of a resistor connected to the end pins, with a central pin connected at an adjustable point along the resistor");
+ setSize( -16, -16, 40, 32 );
+
+ m_p1 = createPin( 32, 0, 180, "p1" );
+
+ m_sliderProp = 0.0;
+ m_resistance = 5000.;
+ m_r1 = createResistance( createPin( -8, -24, 90, "n1" ), m_p1, 1. );
+ m_r2 = createResistance( createPin( -8, 24, 270, "n2" ), m_p1, 1. );
+
+ Slider * s = addSlider( "slider", 0, 100, 5, 50, Qt::Vertical, QRect( 0, -16, 16, 32 ) );
+ m_pSlider = static_cast<QSlider*>(s->widget());
+
+ createProperty( "resistance", Variant::Type::Double );
+ property("resistance")->setCaption( i18n("Resistance") );
+ property("resistance")->setUnit( QChar(0x3a9) );
+ property("resistance")->setMinValue(1e-6);
+ property("resistance")->setValue(1e5);
+
+ addDisplayText( "res", QRect( -56, -8, 40, 16 ), "" );
+}
+
+ECPotentiometer::~ECPotentiometer()
+{
+}
+
+void ECPotentiometer::dataChanged()
+{
+ m_resistance = dataDouble("resistance");
+
+ QString display = QString::number( m_resistance / getMultiplier(m_resistance), 'g', 3 ) + getNumberMag(m_resistance) + QChar(0x3a9);
+ setDisplayText( "res", display );
+
+ sliderValueChanged( "slider", slider("slider")->value() );
+}
+
+void ECPotentiometer::sliderValueChanged( const QString &id, int newValue )
+{
+ if ( id != "slider" )
+ return;
+
+ m_sliderProp = (newValue-50.0)/100.0;
+
+ m_r1->setResistance( m_resistance*(double)newValue/100. );
+ m_r2->setResistance( m_resistance*(double)(100.-newValue)/100. );
+}
+
+void ECPotentiometer::drawShape( QPainter &p )
+{
+ initPainter(p);
+ int _x = int(x());
+ int _y = int(y());
+
+ p.drawRect( _x-14, _y-16, 12, 32 );
+
+ QPointArray pa(3);
+ pa[0] = QPoint( 0, 0 );
+ pa[1] = QPoint( 4, -3 );
+ pa[2] = QPoint( 4, 3 );
+
+ int space = m_pSlider->style().pixelMetric( QStyle::PM_SliderSpaceAvailable, m_pSlider );
+ int base_y = _y + (( angleDegrees() == 0 || angleDegrees() == 270 ) ? 1 : -1) * int( space * m_sliderProp );
+
+ pa.translate( _x+16, base_y );
+
+ QColor c = m_p1->isSelected() ? m_selectedCol : black;
+
+ p.setPen(c);
+ p.setBrush(c);
+ p.drawPolygon(pa);
+
+ p.drawLine( _x+20, base_y, _x+24, base_y );
+ p.drawLine( _x+24, base_y, _x+24, _y );
+
+ deinitPainter(p);
+}
+
+
+
diff --git a/src/electronics/components/ecpotentiometer.h b/src/electronics/components/ecpotentiometer.h
new file mode 100644
index 0000000..e7ca83b
--- /dev/null
+++ b/src/electronics/components/ecpotentiometer.h
@@ -0,0 +1,43 @@
+/***************************************************************************
+ * Copyright (C) 2003-2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef ECPOTENTIOMETER_H
+#define ECPOTENTIOMETER_H
+
+#include "component.h"
+
+class QSlider;
+
+/**
+@short Potentiometer
+@author David Saxton
+*/
+class ECPotentiometer : public Component
+{
+public:
+ ECPotentiometer( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECPotentiometer();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+ virtual void sliderValueChanged( const QString &id, int newValue );
+
+private:
+ void dataChanged();
+ virtual void drawShape( QPainter &p );
+
+ ECNode * m_p1;
+ Resistance *m_r1, *m_r2;
+ double m_resistance;
+ double m_sliderProp;
+ QSlider * m_pSlider;
+};
+#endif
diff --git a/src/electronics/components/ecresistor.cpp b/src/electronics/components/ecresistor.cpp
new file mode 100644
index 0000000..e4ee7a3
--- /dev/null
+++ b/src/electronics/components/ecresistor.cpp
@@ -0,0 +1,76 @@
+/***************************************************************************
+ * Copyright (C) 2003 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "ecresistor.h"
+
+#include "libraryitem.h"
+#include "resistance.h"
+
+#include <klocale.h>
+#include <qpainter.h>
+
+Item* ECResistor::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECResistor( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ECResistor::libraryItem()
+{
+ return new LibraryItem(
+ "ec/resistor",
+ i18n("Resistor"),
+ i18n("Discrete"),
+ "resistor.png",
+ LibraryItem::lit_component,
+ ECResistor::construct );
+}
+
+ECResistor::ECResistor( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, id ? id : "resistor" )
+{
+ m_name = i18n("Resistor");
+ m_desc = i18n("Limits the flow of current, obeying Ohms Law");
+ setSize( -16, -8, 32, 16 );
+
+ init1PinLeft();
+ init1PinRight();
+ m_resistance = createResistance( m_pPNode[0], m_pNNode[0], 1. );
+
+ createProperty( "resistance", Variant::Type::Double );
+ property("resistance")->setCaption( i18n("Resistance") );
+ property("resistance")->setUnit( QChar(0x3a9) );
+ property("resistance")->setValue(1e4);
+ property("resistance")->setMinValue(1e-6);
+
+ addDisplayText( "res", QRect( -16, -22, 32, 12 ), "", false );
+}
+
+ECResistor::~ECResistor()
+{
+}
+
+void ECResistor::dataChanged()
+{
+ double resistance = dataDouble("resistance");
+
+ QString display = QString::number( resistance / getMultiplier(resistance), 'g', 3 ) + getNumberMag(resistance) + QChar(0x3a9);
+ setDisplayText( "res", display );
+
+ m_resistance->setResistance(resistance);
+}
+
+void ECResistor::drawShape( QPainter &p )
+{
+ initPainter(p);
+ p.drawRect( (int)x()-16, (int)y()-6, width(), 12 );
+ deinitPainter(p);
+}
+
+
diff --git a/src/electronics/components/ecresistor.h b/src/electronics/components/ecresistor.h
new file mode 100644
index 0000000..17e799e
--- /dev/null
+++ b/src/electronics/components/ecresistor.h
@@ -0,0 +1,36 @@
+/***************************************************************************
+ * Copyright (C) 2003 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef ECRESISTOR_H
+#define ECRESISTOR_H
+
+#include "component.h"
+
+/**
+@short Simple resistor
+@author David Saxton
+*/
+class ECResistor : public Component
+{
+ public:
+ ECResistor( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECResistor();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+ protected:
+ virtual void dataChanged();
+ virtual void drawShape( QPainter & p );
+
+ Resistance * m_resistance;
+};
+
+#endif
diff --git a/src/electronics/components/ecsevensegment.cpp b/src/electronics/components/ecsevensegment.cpp
new file mode 100644
index 0000000..ec35776
--- /dev/null
+++ b/src/electronics/components/ecsevensegment.cpp
@@ -0,0 +1,210 @@
+/***************************************************************************
+ * Copyright (C) 2003-2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "colorcombo.h"
+#include "diode.h"
+#include "ecled.h"
+#include "ecnode.h"
+#include "ecsevensegment.h"
+#include "libraryitem.h"
+#include "simulator.h"
+
+#include <klocale.h>
+#include <qpainter.h>
+#include <qstring.h>
+
+Item* ECSevenSegment::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECSevenSegment( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ECSevenSegment::libraryItem()
+{
+ return new LibraryItem(
+ "ec/seven_segment",
+ i18n("Seven Segment"),
+ i18n("Outputs"),
+ "seven_segment.png",
+ LibraryItem::lit_component,
+ ECSevenSegment::construct );
+}
+
+ECSevenSegment::ECSevenSegment( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, id ? id : "seven_segment" )
+{
+ m_name = i18n("Seven Segment LED");
+ m_desc = i18n("A seven segment display with a decimal point. This can be configured to either have a common cathode or a common anode.");
+ m_bDynamicContent = true;
+
+ QStringList pins = QStringList::split( ',', "g,f,e,d,"+QString(QChar(0xB7))+",c,b,a" );
+
+ createProperty( "0-color", Variant::Type::Color );
+ property("0-color")->setCaption( i18n("Color") );
+ property("0-color")->setColorScheme( ColorCombo::LED );
+
+ createProperty( "diode-polarity", Variant::Type::Select );
+ property("diode-polarity")->setCaption( i18n("Configuration") );
+ property("diode-polarity")->setAllowed( QStringList::split(',',"Common Cathode,Common Anode") );
+ property("diode-polarity")->setValue("Common Cathode");
+
+ for ( int i=0; i<8; i++ )
+ {
+ m_diodes[i] = 0L;
+ m_nodes[i] = 0L;
+ avg_brightness[i] = 0.;
+ last_brightness[i] = 255;
+ }
+ m_nNode = 0L;
+
+ lastUpdatePeriod = 0.;
+
+ initDIPSymbol( pins, 64 );
+ initDIP(pins);
+
+ m_nNode = createPin( width()/2+offsetX(), height()+8+offsetY(), 270, "-v" );
+
+ for ( int i=0; i<7; i++ )
+ m_nodes[i] = ecNodeWithID( QChar('a'+i) );
+
+ m_nodes[7] = ecNodeWithID(QChar(0xB7));
+
+ m_bCommonCathode = false; // Force update
+}
+
+
+ECSevenSegment::~ECSevenSegment()
+{
+}
+
+
+void ECSevenSegment::dataChanged()
+{
+ QColor color = dataColor("0-color");
+ r = color.red();
+ g = color.green();
+ b = color.blue();
+ r /= 0x100;
+ g /= 0x100;
+ b /= 0x100;
+
+ bool commonCathode = dataString("diode-polarity") == "Common Cathode";
+ if ( commonCathode != m_bCommonCathode )
+ {
+ m_bCommonCathode = commonCathode;
+ for ( int i=0; i<7; i++ )
+ {
+ removeElement( m_diodes[i], false );
+ if (commonCathode)
+ m_diodes[i] = createDiode( m_nodes[i], m_nNode );
+ else
+ m_diodes[i] = createDiode( m_nNode, m_nodes[i] );
+ }
+
+ removeElement( m_diodes[7], false );
+ if (commonCathode)
+ m_diodes[7] = createDiode( m_nodes[7], m_nNode );
+ else
+ m_diodes[7] = createDiode( m_nNode, m_nodes[7] );
+ }
+
+ update();
+}
+
+
+void ECSevenSegment::stepNonLogic()
+{
+ double interval = 1./LINEAR_UPDATE_RATE;
+
+ for ( int i=0; i<8; i++ ) {
+ avg_brightness[i] += ECLed::brightness( m_diodes[i]->current() )*interval;
+ }
+
+ lastUpdatePeriod += interval;
+}
+
+void ECSevenSegment::drawShape( QPainter &p )
+{
+ CNItem::drawShape(p);
+
+ initPainter(p);
+
+ const int _width = 20;
+ const int _height = 32;
+
+ const int x1 = (int)x()+offsetX() + (width()-_width)/2 - 1;
+ const int x2 = x1 + _width;
+ const int y1 = (int)y()+offsetY() + (height()-_height)/2;
+ const int y2 = y1 + _height/2;
+ const int y3 = y1 + _height;
+ const int ds = 2; // "Slope"
+
+// QPen pen;
+// pen.setWidth(2);
+// pen.setCapStyle(Qt::RoundCap);
+// p.setPen(pen);
+
+ if ( lastUpdatePeriod != 0. )
+ {
+ for ( uint i=0; i<8; ++i )
+ {
+ last_brightness[i] = (uint)(avg_brightness[i]/lastUpdatePeriod);
+ }
+ }
+
+ double _b;
+
+ // Top
+ _b = last_brightness[0];
+ p.setPen( QPen( QColor( uint(255-(255-_b)*(1-r)), uint(255-(255-_b)*(1-g)), uint(255-(255-_b)*(1-b)) ), 2 ) );
+ p.drawLine( x1+3+ds, y1+0, x2-3+ds, y1+0 );
+
+ // Top right
+ _b = last_brightness[1];
+ p.setPen( QPen( QColor( uint(255-(255-_b)*(1-r)), uint(255-(255-_b)*(1-g)), uint(255-(255-_b)*(1-b)) ), 2 ) );
+ p.drawLine( x2+0+ds, y1+3, x2+0, y2-3 );
+
+ // Bottom right
+ _b = last_brightness[2];
+ p.setPen( QPen( QColor( uint(255-(255-_b)*(1-r)), uint(255-(255-_b)*(1-g)), uint(255-(255-_b)*(1-b)) ), 2 ) );
+ p.drawLine( x2+0, y2+3, x2+0-ds, y3-3 );
+
+ // Bottom
+ _b = last_brightness[3];
+ p.setPen( QPen( QColor( uint(255-(255-_b)*(1-r)), uint(255-(255-_b)*(1-g)), uint(255-(255-_b)*(1-b)) ), 2 ) );
+ p.drawLine( x2-3-ds, y3+0, x1+3-ds, y3+0 );
+
+ // Bottom left
+ _b = last_brightness[4];
+ p.setPen( QPen( QColor( uint(255-(255-_b)*(1-r)), uint(255-(255-_b)*(1-g)), uint(255-(255-_b)*(1-b)) ), 2 ) );
+ p.drawLine( x1+0-ds, y3-3, x1+0, y2+3 );
+
+ // Top left
+ _b = last_brightness[5];
+ p.setPen( QPen( QColor( uint(255-(255-_b)*(1-r)), uint(255-(255-_b)*(1-g)), uint(255-(255-_b)*(1-b)) ), 2 ) );
+ p.drawLine( x1+0, y2-3, x1+0+ds, y1+3 );
+
+ // Middle
+ _b = last_brightness[6];
+ p.setPen( QPen( QColor( uint(255-(255-_b)*(1-r)), uint(255-(255-_b)*(1-g)), uint(255-(255-_b)*(1-b)) ), 2 ) );
+ p.drawLine( x1+3, y2+0, x2-3, y2+0 );
+
+ // Decimal point
+ _b = last_brightness[7];
+ p.setBrush( QBrush( QColor( uint(255-(255-_b)*(1-r)), uint(255-(255-_b)*(1-g)), uint(255-(255-_b)*(1-b)) ) ) );
+ p.setPen( Qt::NoPen );
+ p.drawPie( x2+3, y3-2, 3, 3, 0, 16*360 );
+
+ lastUpdatePeriod = 0.;
+ for ( uint i=0; i<8; ++i ) {
+ avg_brightness[i] = 0.;
+ }
+
+ deinitPainter(p);
+}
diff --git a/src/electronics/components/ecsevensegment.h b/src/electronics/components/ecsevensegment.h
new file mode 100644
index 0000000..7041c9a
--- /dev/null
+++ b/src/electronics/components/ecsevensegment.h
@@ -0,0 +1,50 @@
+/***************************************************************************
+ * Copyright (C) 2003-2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef ECSEVENSEGMENT_H
+#define ECSEVENSEGMENT_H
+
+#include "component.h"
+
+class Diode;
+class ECNode;
+
+/**
+@short Seven segment display component
+@author David Saxton
+*/
+class ECSevenSegment : public Component
+{
+public:
+ ECSevenSegment( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECSevenSegment();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+ virtual void stepNonLogic();
+ virtual bool doesStepNonLogic() const { return true; }
+ virtual void dataChanged();
+ virtual bool canFlip() const { return true; }
+
+private:
+ virtual void drawShape( QPainter &p );
+
+ bool m_bCommonCathode;
+ double lastUpdatePeriod;
+ double avg_brightness[8];
+ uint last_brightness[8];
+ Diode *m_diodes[8];
+ ECNode *m_nodes[8];
+ ECNode *m_nNode;
+ double r, g, b;
+};
+
+#endif
diff --git a/src/electronics/components/ecsignallamp.cpp b/src/electronics/components/ecsignallamp.cpp
new file mode 100644
index 0000000..c7034f7
--- /dev/null
+++ b/src/electronics/components/ecsignallamp.cpp
@@ -0,0 +1,86 @@
+/***************************************************************************
+ * Copyright (C) 2003-2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+
+#include "ecnode.h"
+#include "ecsignallamp.h"
+#include "element.h"
+#include "libraryitem.h"
+#include "pin.h"
+
+#include <klocale.h>
+#include <qpainter.h>
+
+Item* ECSignalLamp::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECSignalLamp( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ECSignalLamp::libraryItem()
+{
+ return new LibraryItem(
+ QString("ec/signal_lamp"),
+ i18n("Signal Lamp"),
+ i18n("Outputs"),
+ "signal_lamp.png",
+ LibraryItem::lit_component,
+ ECSignalLamp::construct );
+}
+
+ECSignalLamp::ECSignalLamp( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, (id) ? id : "signal_lamp" )
+{
+ m_name = i18n("Signal Lamp");
+ m_desc = i18n("A simple filament signal lamp, with a 100 ohms series resistance.");
+ setSize( -8, -8, 16, 16 );
+
+ init1PinLeft();
+ init1PinRight();
+
+ createResistance( m_pPNode[0], m_pNNode[0], 100. );
+
+ advanceSinceUpdate = 0;
+ avgPower = 0.;
+ m_bDynamicContent = true;
+}
+
+ECSignalLamp::~ECSignalLamp()
+{
+}
+
+void ECSignalLamp::stepNonLogic()
+{
+ const double voltage = m_pPNode[0]->pin()->voltage()-m_pNNode[0]->pin()->voltage();
+ avgPower = QABS(avgPower*advanceSinceUpdate + (voltage*voltage/100))/++advanceSinceUpdate;
+}
+
+void ECSignalLamp::drawShape( QPainter &p )
+{
+ initPainter(p);
+
+ int _x = int(x());
+ int _y = int(y());
+
+ // Calculate the brightness as a linear function of power, bounded below by
+ // 25 milliWatts and above by 500 milliWatts.
+ int brightness = (avgPower<0.025) ? 255 : ((avgPower>0.5) ? 0 : (int)(255*(1-((avgPower-0.025)/0.475))));
+ advanceSinceUpdate = 0;
+
+ p.setBrush( QColor( 255, 255, brightness ) );
+ p.drawEllipse( _x-8, _y-8, 16, 16 );
+
+ // 2*sqrt(2) = 2.828427125...
+ int pos = 8 - int(16/2.828);
+
+ p.drawLine( _x-8+pos, _y-8+pos, _x+8-pos, _y+8-pos );
+ p.drawLine( _x+8-pos, _y-8+pos, _x-8+pos, _y+8-pos );
+
+ deinitPainter(p);
+}
diff --git a/src/electronics/components/ecsignallamp.h b/src/electronics/components/ecsignallamp.h
new file mode 100644
index 0000000..e56d724
--- /dev/null
+++ b/src/electronics/components/ecsignallamp.h
@@ -0,0 +1,40 @@
+/***************************************************************************
+ * Copyright (C) 2003-2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef ECSIGNALLAMP_H
+#define ECSIGNALLAMP_H
+
+#include "component.h"
+
+class Resistance;
+
+/**
+@short Signal Lamp - glows when current flows
+@author David Saxton
+*/
+class ECSignalLamp : public Component
+{
+public:
+ ECSignalLamp( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECSignalLamp();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+ virtual void stepNonLogic();
+ virtual bool doesStepNonLogic() const { return true; }
+
+private:
+ void drawShape( QPainter &p );
+ double avgPower;
+ uint advanceSinceUpdate;
+};
+
+#endif
diff --git a/src/electronics/components/ecsubcircuit.cpp b/src/electronics/components/ecsubcircuit.cpp
new file mode 100644
index 0000000..a69e720
--- /dev/null
+++ b/src/electronics/components/ecsubcircuit.cpp
@@ -0,0 +1,130 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "canvasitemparts.h"
+#include "circuitdocument.h"
+#include "ecsubcircuit.h"
+#include "node.h"
+#include "libraryitem.h"
+#include "subcircuits.h"
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <qfile.h>
+
+Item* ECSubcircuit::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECSubcircuit( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ECSubcircuit::libraryItem()
+{
+ return new LibraryItem(
+ QString::QString("ec/subcircuit"),
+ QString::null,
+ QString::null,
+ QString::null,
+ LibraryItem::lit_subcircuit,
+ ECSubcircuit::construct );
+}
+
+ECSubcircuit::ECSubcircuit( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, (id) ? id : "subcircuit" )
+{
+ m_name = i18n("Subcircuit");
+
+ createProperty( "id", Variant::Type::Int );
+ property("id")->setMinValue(1);
+ property("id")->setMaxValue(1<<15);
+ property("id")->setValue(1);
+ property("id")->setHidden(true);
+}
+
+
+ECSubcircuit::~ECSubcircuit()
+{
+}
+
+
+void ECSubcircuit::removeItem()
+{
+ emit subcircuitDeleted();
+ Component::removeItem();
+}
+
+
+void ECSubcircuit::setNumExtCon( unsigned numExtCon )
+{
+ m_conNames.resize(numExtCon);
+
+ // Remove old pins
+ const NodeMap::iterator nodeMapEnd = m_nodeMap.end();
+ for ( NodeMap::iterator it = m_nodeMap.begin(); it != nodeMapEnd; ++it )
+ {
+ p_icnDocument->appendDeleteList( p_icnDocument->nodeWithID(it.data().id) );
+ }
+ p_icnDocument->flushDeleteList();
+ m_nodeMap.clear();
+
+ QStringList pins;
+ for ( unsigned i=0; i<numExtCon; ++i )
+ {
+ pins += QString::number(i);
+ }
+
+ initDIPSymbol( pins, 80 );
+
+ // We don't want the text that the dip symbol gave us as we initialize it later...
+ for ( unsigned i = 0; i < numExtCon; ++i )
+ removeDisplayText( QString::number(i) );
+
+ initDIP(pins);
+}
+
+
+void ECSubcircuit::dataChanged()
+{
+ int subcircuitId = dataInt("id");
+ if ( subcircuitId == -1 ) {
+ return;
+ }
+ emit subcircuitDeleted();
+ Subcircuits::initECSubcircuit( subcircuitId, this );
+}
+
+
+void ECSubcircuit::setExtConName( unsigned numId, const QString & name )
+{
+ if ( numId > m_conNames.size() )
+ return;
+
+ m_conNames[numId] = name;
+}
+
+
+void ECSubcircuit::doneSCInit()
+{
+ QStringList pins;
+ for ( unsigned i = 0; i < m_conNames.size(); ++i )
+ pins << m_conNames[i];
+ initDIPSymbol( pins, 80 );
+}
+
+
+void ECSubcircuit::drawShape( QPainter &p )
+{
+ Component::drawShape(p);
+}
+
+
+#include "ecsubcircuit.moc"
+
+
+
diff --git a/src/electronics/components/ecsubcircuit.h b/src/electronics/components/ecsubcircuit.h
new file mode 100644
index 0000000..eaf21ec
--- /dev/null
+++ b/src/electronics/components/ecsubcircuit.h
@@ -0,0 +1,61 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef ECSUBCIRCUIT_H
+#define ECSUBCIRCUIT_H
+
+#include <component.h>
+
+#include <qvaluevector.h>
+
+/**
+"Container" component for subcircuits
+@author David Saxton
+*/
+class ECSubcircuit : public Component
+{
+Q_OBJECT
+public:
+ ECSubcircuit( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECSubcircuit();
+ virtual bool canFlip() const { return true; }
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+ /**
+ * Create numExtCon nodes, deleting any old ones
+ */
+ void setNumExtCon( unsigned numExtCon );
+ /**
+ * Give the connecting node at position numId the given name
+ */
+ void setExtConName( unsigned numId, const QString & name );
+ /**
+ * Called from SubcircuitData once the subcircuit has been fully attached
+ */
+ void doneSCInit();
+
+public slots:
+ virtual void removeItem();
+
+signals:
+ /**
+ * Emitted when the current subcircuit is deleted
+ */
+ void subcircuitDeleted();
+
+protected:
+ virtual void dataChanged();
+ virtual void drawShape( QPainter &p );
+ QValueVector<QString> m_conNames;
+};
+
+#endif
diff --git a/src/electronics/components/ecvoltagesignal.cpp b/src/electronics/components/ecvoltagesignal.cpp
new file mode 100644
index 0000000..c338f36
--- /dev/null
+++ b/src/electronics/components/ecvoltagesignal.cpp
@@ -0,0 +1,95 @@
+/***************************************************************************
+ * Copyright (C) 2003-2004 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "ecnode.h"
+#include "ecvoltagesignal.h"
+#include "libraryitem.h"
+#include "pin.h"
+#include "simulator.h"
+#include "voltagesignal.h"
+
+#include <klocale.h>
+#include <qpainter.h>
+
+const double conductance = 1e5; // Internal resistance
+
+Item* ECVoltageSignal::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECVoltageSignal( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ECVoltageSignal::libraryItem()
+{
+ return new LibraryItem(
+ QString("ec/voltage_signal"),
+ i18n("Voltage Signal"),
+ i18n("Sources"),
+ "voltagesignal.png",
+ LibraryItem::lit_component,
+ ECVoltageSignal::construct );
+}
+
+ECVoltageSignal::ECVoltageSignal( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, (id) ? id : "voltage_signal" )
+{
+ m_name = i18n("Voltage Signal");
+ m_desc = i18n("Provides a variety of voltage signals.");
+ setSize( -8, -8, 16, 16 );
+
+ init1PinLeft();
+ init1PinRight();
+
+ m_pNNode[0]->pin()->setGroundType( Pin::gt_medium );
+ m_voltageSignal = createVoltageSignal( m_pNNode[0], m_pPNode[0], 0. );
+ m_voltageSignal->setStep( 1./LINEAR_UPDATE_RATE, ElementSignal::st_sinusoidal, 50. );
+
+ createProperty( "frequency", Variant::Type::Double );
+ property("frequency")->setCaption( i18n("Frequency") );
+ property("frequency")->setUnit("Hz");
+ property("frequency")->setMinValue(1e-9);
+ property("frequency")->setMaxValue(1e3);
+ property("frequency")->setValue(50.0);
+
+ createProperty( "voltage", Variant::Type::Double );
+ property("voltage")->setCaption( i18n("Voltage Range") );
+ property("voltage")->setUnit("V");
+ property("voltage")->setMinValue(-1e12);
+ property("voltage")->setMaxValue(1e12);
+ property("voltage")->setValue(5.0);
+
+ addDisplayText( "~", QRect( -8, -8, 16, 16 ), "~" );
+ addDisplayText( "voltage", QRect( -16, -24, 32, 16 ), "" );
+}
+
+
+ECVoltageSignal::~ECVoltageSignal()
+{
+}
+
+void ECVoltageSignal::dataChanged()
+{
+ const double voltage = dataDouble("voltage");
+ const double frequency = dataDouble("frequency");
+
+ QString display = QString::number( voltage / getMultiplier(voltage), 'g', 3 ) + getNumberMag(voltage) + "V";
+ setDisplayText( "voltage", display );
+
+ m_voltageSignal->setStep( 1./LINEAR_UPDATE_RATE, ElementSignal::st_sinusoidal, frequency );
+ m_voltageSignal->setVoltage(voltage);
+}
+
+
+void ECVoltageSignal::drawShape( QPainter &p )
+{
+ initPainter(p);
+ p.drawEllipse( (int)x()-8, (int)y()-8, width(), height() );
+ deinitPainter(p);
+}
+
diff --git a/src/electronics/components/ecvoltagesignal.h b/src/electronics/components/ecvoltagesignal.h
new file mode 100644
index 0000000..7102132
--- /dev/null
+++ b/src/electronics/components/ecvoltagesignal.h
@@ -0,0 +1,36 @@
+/***************************************************************************
+ * Copyright (C) 2003-2004 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef ECVOLTAGESIGNAL_H
+#define ECVOLTAGESIGNAL_H
+
+#include "component.h"
+
+/**
+@short Provides an alternating voltage source
+@author David Saxton
+*/
+class ECVoltageSignal : public Component
+{
+public:
+ ECVoltageSignal( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECVoltageSignal();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+protected:
+ virtual void drawShape( QPainter &p );
+ void dataChanged();
+
+ VoltageSignal *m_voltageSignal;
+};
+
+#endif
diff --git a/src/electronics/components/ecvoltagesource.cpp b/src/electronics/components/ecvoltagesource.cpp
new file mode 100644
index 0000000..4b8c543
--- /dev/null
+++ b/src/electronics/components/ecvoltagesource.cpp
@@ -0,0 +1,93 @@
+/***************************************************************************
+ * Copyright (C) 2003 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "ecvoltagesource.h"
+
+#include "ecnode.h"
+#include "voltagesource.h"
+#include "libraryitem.h"
+#include "pin.h"
+
+#include <klocale.h>
+#include <qpainter.h>
+
+const double conductance = 1e5; // Internal resistance
+
+Item* ECCell::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECCell( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ECCell::libraryItem()
+{
+ QStringList ids;
+ ids << "ec/battery" << "ec/cell";
+ return new LibraryItem(
+ ids,
+ i18n("Battery"),
+ i18n("Sources"),
+ "cell.png",
+ LibraryItem::lit_component,
+ ECCell::construct );
+}
+
+ECCell::ECCell( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, (id) ? id : "cell" )
+{
+ m_name = i18n("Battery");
+ m_desc = i18n("Provides a potential-difference.");
+ setSize( -8, -8, 16, 16 );
+ voltage = 0;
+
+ init1PinLeft();
+ init1PinRight();
+
+ m_pNNode[0]->pin()->setGroundType( Pin::gt_medium );
+ m_voltageSource = createVoltageSource( m_pNNode[0], m_pPNode[0], voltage );
+
+ createProperty( "voltage", Variant::Type::Double );
+ property("voltage")->setUnit("V");
+ property("voltage")->setCaption( i18n("Voltage") );
+ property("voltage")->setMinValue(-1e12);
+ property("voltage")->setMaxValue(1e12);
+ property("voltage")->setValue(5.0);
+
+ addDisplayText( "voltage", QRect( -16, -24, 32, 16 ), "" );
+}
+
+ECCell::~ECCell()
+{
+}
+
+void ECCell::dataChanged()
+{
+ voltage = dataDouble("voltage");
+ m_voltageSource->setVoltage(voltage);
+
+ QString display = QString::number( voltage / getMultiplier(voltage), 'g', 3 ) + getNumberMag(voltage) + "V";
+ setDisplayText( "voltage", display );
+}
+
+void ECCell::drawShape( QPainter &p )
+{
+ initPainter(p);
+
+ int _x = (int)x()-8;
+ int _y = (int)y()-24;
+
+ p.drawLine( _x, _y+20, _x, _y+28 );
+ p.drawLine( _x+5, _y+16, _x+5, _y+32 );
+ p.drawLine( _x+10, _y+20, _x+10, _y+28 );
+ p.drawLine( _x+15, _y+16, _x+15, _y+32 );
+
+ deinitPainter(p);
+// p.drawPolyline( areaPoints() );
+}
+
diff --git a/src/electronics/components/ecvoltagesource.h b/src/electronics/components/ecvoltagesource.h
new file mode 100644
index 0000000..4ba87ef
--- /dev/null
+++ b/src/electronics/components/ecvoltagesource.h
@@ -0,0 +1,37 @@
+/***************************************************************************
+ * Copyright (C) 2003 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef ECCELL_H
+#define ECCELL_H
+
+#include "component.h"
+
+/**
+@short Electrical cell
+Simple electrical cell that simulates a PD and internal resistance
+@author David Saxton
+*/
+class ECCell : public Component
+{
+public:
+ ECCell( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECCell();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+private:
+ void dataChanged();
+ virtual void drawShape( QPainter &p );
+ VoltageSource *m_voltageSource;
+ double voltage;
+};
+
+#endif
diff --git a/src/electronics/components/externalconnection.cpp b/src/electronics/components/externalconnection.cpp
new file mode 100644
index 0000000..596727a
--- /dev/null
+++ b/src/electronics/components/externalconnection.cpp
@@ -0,0 +1,78 @@
+/***************************************************************************
+ * Copyright (C) 2004 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "externalconnection.h"
+#include "libraryitem.h"
+
+#include <klocale.h>
+#include <qpainter.h>
+
+Item* ExternalConnection::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ExternalConnection( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ExternalConnection::libraryItem()
+{
+ return new LibraryItem(
+ "ec/external_connection",
+ i18n("External Connection"),
+ i18n("Connections"),
+ "external_connection.png",
+ LibraryItem::lit_component,
+ ExternalConnection::construct );
+}
+
+ExternalConnection::ExternalConnection( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, id ? id : "external_connection" )
+{
+ m_name = i18n("External Connection");
+ m_desc = i18n("Point to connect the circuit to an external entity - e.g. a mechanical component or as part of a subcircuit.");
+ setSize( -8, -8, 16, 16 );
+
+ createProperty( "name", Variant::Type::Combo );
+ property("name")->setCaption( i18n("Name") );
+ property("name")->setValue("ExtCon");
+
+ init1PinLeft();
+
+ addDisplayText( "name", QRect( -24, 8, 3*width(), 16 ), "ExtCon" );
+}
+
+ExternalConnection::~ExternalConnection()
+{
+}
+
+
+void ExternalConnection::dataChanged()
+{
+ QString name = dataString("name");
+
+ QRect r( -width(), 16, 3*width(), 16 );
+ setDisplayText( "name", name );
+}
+
+
+void ExternalConnection::drawShape( QPainter &p )
+{
+ initPainter(p);
+ int _x = (int)x()-8;
+ int _y = (int)y()-8;
+ p.drawEllipse( _x, _y, width(), height() );
+
+ p.drawLine( _x+3, _y+6, _x+12, _y+6 );
+ p.drawLine( _x+8, _y+3, _x+12, _y+6 );
+
+ p.drawLine( _x+3, _y+9, _x+12, _y+9 );
+ p.drawLine( _x+3, _y+9, _x+8, _y+12 );
+
+ deinitPainter(p);
+}
+
diff --git a/src/electronics/components/externalconnection.h b/src/electronics/components/externalconnection.h
new file mode 100644
index 0000000..9b733fc
--- /dev/null
+++ b/src/electronics/components/externalconnection.h
@@ -0,0 +1,35 @@
+/***************************************************************************
+ * Copyright (C) 2004 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef EXTERNALCONNECTION_H
+#define EXTERNALCONNECTION_H
+
+#include <component.h>
+
+/**
+For connecting to something "outside" - e.g. a mechanical component, or as part
+of a circuit part
+@author David Saxton
+*/
+class ExternalConnection : public Component
+{
+public:
+ ExternalConnection( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ExternalConnection();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+private:
+ void dataChanged();
+ virtual void drawShape( QPainter &p );
+};
+
+#endif
diff --git a/src/electronics/components/flipflop.cpp b/src/electronics/components/flipflop.cpp
new file mode 100644
index 0000000..5c55baf
--- /dev/null
+++ b/src/electronics/components/flipflop.cpp
@@ -0,0 +1,347 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "flipflop.h"
+#include "icndocument.h"
+#include "logic.h"
+#include "libraryitem.h"
+#include "node.h"
+#include "simulator.h"
+
+#include <kiconloader.h>
+#include <klocale.h>
+#include <qpainter.h>
+
+
+//BEGIN class ECDFlipFlop
+Item* ECDFlipFlop::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECDFlipFlop( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ECDFlipFlop::libraryItem()
+{
+ return new LibraryItem(
+ "ec/d_flipflop",
+ i18n("D Flip-Flop"),
+ i18n("Integrated Circuits"),
+ "ic3.png",
+ LibraryItem::lit_component,
+ ECDFlipFlop::construct );
+}
+
+ECDFlipFlop::ECDFlipFlop( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, (id) ? id : "d_flipflop" )
+{
+ m_name = i18n("D-Type Flip-Flop");
+ m_desc = i18n("The output state is set from the input state when the clock is pulsed.");
+
+ setSize( -32, -24, 64, 48 );
+
+ init2PinLeft( -8, 8 );
+ init2PinRight( -8, 8 );
+
+ m_prevD[0] = m_prevD[1] = false;
+ m_whichPrevD = 0;
+ m_prevDSimTime = 0;
+ m_pSimulator = Simulator::self();
+
+ m_bPrevClock = false;
+ m_pD = createLogicIn( m_pNNode[0] );
+ m_pClock = createLogicIn( m_pNNode[1] );
+ m_pQ = createLogicOut( m_pPNode[0], false );
+ m_pQBar = createLogicOut( m_pPNode[1], false );
+
+ setp = createLogicIn( createPin( 0, -32, 90, "set" ) );
+ rstp = createLogicIn( createPin( 0, 32, 270, "rst" ) );
+
+ addDisplayText( "D", QRect( -32, -16, 20, 16 ), "D" );
+ addDisplayText( ">", QRect( -32, 0, 20, 16 ), ">" );
+ addDisplayText( "Q", QRect( 12, -16, 20, 16 ), "Q" );
+ addDisplayText( "Q'", QRect( 12, 0, 20, 16 ), "Q'" );
+ addDisplayText( "Set", QRect( -16, -20, 32, 16 ), "Set" );
+ addDisplayText( "Rst", QRect( -16, 4, 32, 16 ), "Rst" );
+
+ m_pD->setCallback( this, (CallbackPtr)(&ECDFlipFlop::inputChanged) );
+ m_pClock->setCallback( this, (CallbackPtr)(&ECDFlipFlop::clockChanged) );
+ setp->setCallback( this, (CallbackPtr)(&ECDFlipFlop::asyncChanged) );
+ rstp->setCallback( this, (CallbackPtr)(&ECDFlipFlop::asyncChanged) );
+
+ inStateChanged(false);
+}
+
+ECDFlipFlop::~ECDFlipFlop()
+{
+}
+
+void ECDFlipFlop::asyncChanged(bool)
+{
+ bool set = setp->isHigh();
+ bool rst = rstp->isHigh();
+ if(set || rst)
+ {
+ m_pQ->setHigh(set);
+ m_pQBar->setHigh(rst);
+ }
+}
+
+void ECDFlipFlop::inputChanged( bool newState )
+{
+ unsigned long long simTime = m_pSimulator->time();
+ if ( (simTime == m_prevDSimTime) && (newState == m_prevD[m_whichPrevD]) )
+ return;
+
+ m_prevDSimTime = simTime;
+ m_whichPrevD = 1-m_whichPrevD;
+ m_prevD[m_whichPrevD] = newState;
+}
+
+void ECDFlipFlop::clockChanged( bool newState )
+{
+ bool set = setp->isHigh();
+ bool rst = rstp->isHigh();
+
+ bool fallingEdge = m_bPrevClock && !newState;
+ m_bPrevClock = newState;
+
+ if( set || rst ) return;
+
+ if (fallingEdge)
+ {
+ unsigned long long simTime = m_pSimulator->time();
+ bool d = ( simTime == m_prevDSimTime ) ? m_prevD[1-m_whichPrevD] : m_prevD[m_whichPrevD];
+
+ m_pQ->setHigh(d);
+ m_pQBar->setHigh(!d);
+ }
+}
+
+void ECDFlipFlop::inStateChanged(bool)
+{
+ // Only called when the flipflop is created.
+ m_pQ->setHigh(false);
+ m_pQBar->setHigh(true);
+}
+//END class ECDFlipFlop
+
+
+//BEGIN class ECJKFlipFlop
+Item* ECJKFlipFlop::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECJKFlipFlop( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ECJKFlipFlop::libraryItem()
+{
+ return new LibraryItem(
+ QString::QString("ec/jk_flipflop"),
+ i18n("JK Flip-Flop"),
+ i18n("Integrated Circuits"),
+ "ic3.png",
+ LibraryItem::lit_component,
+ ECJKFlipFlop::construct );
+}
+
+ECJKFlipFlop::ECJKFlipFlop( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, (id) ? id : "jk_flipflop" )
+{
+ m_name = i18n("JK-Type Flip-Flop");
+ m_desc = i18n("The output state is set according to J and K when the clock is pulsed.");
+
+ setSize( -32, -32, 64, 64 );
+
+ init3PinLeft( -16, 0, 16 );
+ init2PinRight( -16, 16 );
+
+ m_pJ = createLogicIn( m_pNNode[0] );
+ m_pClock = createLogicIn( m_pNNode[1] );
+ m_pK = createLogicIn( m_pNNode[2] );
+
+ m_pQ = createLogicOut( m_pPNode[0], false );
+ m_pQBar = createLogicOut( m_pPNode[1], false );
+
+ setp = createLogicIn( createPin( 0, -40, 90, "set" ) );
+ rstp = createLogicIn( createPin( 0, 40, 270, "rst" ) );
+
+ addDisplayText( "J", QRect( -32, -24, 20, 16 ), "J" );
+ addDisplayText( ">", QRect( -32, -8, 20, 16 ), ">" );
+ addDisplayText( "K", QRect( -32, 8, 20, 16 ), "K" );
+ addDisplayText( "Q", QRect( 12, -24, 20, 16 ), "Q" );
+ addDisplayText( "Q'", QRect( 12, 8, 20, 16 ), "Q'" );
+ addDisplayText( "Set", QRect( -16, -28, 32, 16 ), "Set" );
+ addDisplayText( "Rst", QRect( -16, 12, 32, 16 ), "Rst" );
+
+ m_pClock->setCallback( this, (CallbackPtr)(&ECJKFlipFlop::clockChanged) );
+ setp->setCallback( this, (CallbackPtr)(&ECJKFlipFlop::asyncChanged) );
+ rstp->setCallback( this, (CallbackPtr)(&ECJKFlipFlop::asyncChanged) );
+
+ inStateChanged(false);
+}
+
+ECJKFlipFlop::~ECJKFlipFlop()
+{
+}
+
+void ECJKFlipFlop::clockChanged(bool newvalue)
+{
+ bool j = m_pJ->isHigh();
+ bool k = m_pK->isHigh();
+ bool set = setp->isHigh();
+ bool rst = rstp->isHigh();
+
+ if( set || rst ) return;
+
+// a JK flip-flop change state when clock do 1->0
+ if (!newvalue && (j || k)) {
+ if ( j && k ) {
+ m_pQ->setHigh(!prev_state);
+ m_pQBar->setHigh(prev_state);
+ prev_state = !prev_state;
+ } else {
+ // (J=1 && K=0) || (J=0 && K=1)
+ m_pQ->setHigh(j);
+ m_pQBar->setHigh(k);
+ prev_state = j;
+ }
+ }
+}
+
+void ECJKFlipFlop::asyncChanged(bool)
+{
+ bool set = setp->isHigh();
+ bool rst = rstp->isHigh();
+
+ if (set || rst) {
+ m_pQ->setHigh(set);
+ m_pQBar->setHigh(rst);
+ prev_state = set;
+ }
+}
+
+void ECJKFlipFlop::inStateChanged(bool)
+{
+ m_pQBar->setHigh(true);
+ m_pQ->setHigh(false);
+ prev_state = false;
+}
+//END class ECJKFlipFlop
+
+
+//BEGIN class ECSRFlipFlop
+Item* ECSRFlipFlop::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECSRFlipFlop( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ECSRFlipFlop::libraryItem()
+{
+ return new LibraryItem(
+ QString::QString("ec/sr_flipflop"),
+ i18n("SR Flip-Flop"),
+ i18n("Integrated Circuits"),
+ "ic3.png",
+ LibraryItem::lit_component,
+ ECSRFlipFlop::construct );
+}
+
+ECSRFlipFlop::ECSRFlipFlop( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, (id) ? id : "sr_flipflop" )
+{
+ m_name = i18n("SR Flip-Flop");
+ m_desc = i18n("The output is made high by holding <i>set</i> high, and low by holding <i>reset</i> high.");
+
+ setSize( -24, -24, 48, 48 );
+
+ init2PinLeft( -8, 8 );
+ init2PinRight( -8, 8 );
+
+ m_pS = createLogicIn( m_pNNode[0] );
+ m_pR = createLogicIn( m_pNNode[1] );
+ m_pQ = createLogicOut( m_pPNode[0], true );
+ m_pQBar = createLogicOut( m_pPNode[1], false );
+
+ old_q1 = true;
+ old_q2 = false;
+ m_pQ->setHigh(old_q1);
+ m_pQBar->setHigh(old_q2);
+
+ addDisplayText( "S", QRect( -24, -16, 20, 16 ), "S" );
+ addDisplayText( "R", QRect( -24, 0, 20, 16 ), "R" );
+ addDisplayText( "Q", QRect( 4, -16, 20, 16 ), "Q" );
+ addDisplayText( "Q'", QRect( 4, 0, 20, 16 ), "Q'" );
+
+ m_pS->setCallback( this, (CallbackPtr)(&ECSRFlipFlop::inStateChanged) );
+ m_pR->setCallback( this, (CallbackPtr)(&ECSRFlipFlop::inStateChanged) );
+ m_pQ->setCallback( this, (CallbackPtr)(&ECSRFlipFlop::inStateChanged) );
+ m_pQBar->setCallback( this, (CallbackPtr)(&ECSRFlipFlop::inStateChanged) );
+}
+
+ECSRFlipFlop::~ECSRFlipFlop()
+{
+}
+
+void ECSRFlipFlop::inStateChanged(bool)
+{
+ // Q = v_q1, Q-bar = v_q2
+ bool new_q1 = false;
+ bool new_q2 = false;
+
+ bool s = m_pS->isHigh();
+ bool r = m_pR->isHigh();
+ bool q1 = m_pQ->isHigh();
+ bool q2 = m_pQBar->isHigh();
+
+ // Easy ones to do :-)
+ if (!q1) new_q2 = true;
+ if (!q2) new_q1 = true;
+
+ if ( q1 && q2 )
+ {
+ if ( s && !r )
+ {
+ new_q1 = true;
+ new_q2 = false;
+ }
+ else if ( !s && r )
+ {
+ new_q1 = false;
+ new_q2 = true;
+ }
+ else if ( s && r )
+ {
+ new_q1 = old_q1;
+ new_q2 = old_q2;
+ }
+ else if ( !s && !r )
+ {
+ new_q1 = false;
+ new_q2 = false;
+ }
+ }
+ else if ( q1 && !q2 )
+ {
+ // Note: We only need to set the value of v_q2
+ if ( r && !s ) new_q2 = true;
+ else new_q2 = false;
+ }
+ else if ( !q1 && q2 )
+ {
+ // Note: We only need to set the value of v_q1
+ if ( s && !r ) new_q1 = true;
+ else new_q1 = false;
+ }
+
+ old_q1 = new_q1;
+ old_q2 = new_q2;
+
+ m_pQ->setHigh(new_q1);
+ m_pQBar->setHigh(new_q2);
+}
+//END class ECSRFlipFlop
diff --git a/src/electronics/components/flipflop.h b/src/electronics/components/flipflop.h
new file mode 100644
index 0000000..7b9d5b7
--- /dev/null
+++ b/src/electronics/components/flipflop.h
@@ -0,0 +1,107 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef FLIPFLOP_H
+#define FLIPFLOP_H
+
+#include "component.h"
+#include "logic.h"
+
+class Simulator;
+
+/**
+@short Boolean D-Type Flip-Flop
+@author David Saxton
+*/
+class ECDFlipFlop : public CallbackClass, public Component
+{
+public:
+ ECDFlipFlop( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECDFlipFlop();
+ virtual bool canFlip() const { return true; }
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+private:
+ void inputChanged( bool newState );
+ void inStateChanged( bool newState );
+ void asyncChanged(bool newState );
+ void clockChanged(bool newState );
+
+ LogicIn *m_pD;
+ LogicIn *m_pClock;
+ LogicOut *m_pQ;
+ LogicOut *m_pQBar;
+ LogicIn *setp;
+ LogicIn *rstp;
+ bool m_bPrevClock;
+
+ bool m_prevD[2];
+ unsigned m_whichPrevD:1;
+ unsigned long long m_prevDSimTime;
+ Simulator * m_pSimulator;
+};
+
+
+/**
+@short Boolean JK-Type Flip-Flop
+@author Couriousous
+*/
+class ECJKFlipFlop : public CallbackClass, public Component
+{
+public:
+ ECJKFlipFlop( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECJKFlipFlop();
+ virtual bool canFlip() const { return true; }
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+private:
+ void inStateChanged( bool newState );
+ void asyncChanged(bool newState );
+ void clockChanged(bool newState );
+ bool prev_state;
+ LogicIn *m_pJ;
+ LogicIn *m_pClock;
+ LogicIn *m_pK;
+ LogicIn *setp;
+ LogicIn *rstp;
+ LogicOut *m_pQ;
+ LogicOut *m_pQBar;
+};
+
+
+/**
+@short Boolean Set-Reset Flip-Flop
+@author David Saxton
+*/
+class ECSRFlipFlop : public CallbackClass, public Component
+{
+public:
+ ECSRFlipFlop( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECSRFlipFlop();
+ virtual bool canFlip() const { return true; }
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+protected:
+ void inStateChanged( bool newState );
+ LogicIn * m_pS;
+ LogicIn * m_pR;
+ LogicOut * m_pQ;
+ LogicOut * m_pQBar;
+ bool old_q1;
+ bool old_q2;
+};
+
+#endif
diff --git a/src/electronics/components/fulladder.cpp b/src/electronics/components/fulladder.cpp
new file mode 100644
index 0000000..ad5e40c
--- /dev/null
+++ b/src/electronics/components/fulladder.cpp
@@ -0,0 +1,91 @@
+/***************************************************************************
+ * Copyright (C) 2004 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "fulladder.h"
+
+#include "logic.h"
+#include "libraryitem.h"
+
+#include <kiconloader.h>
+#include <klocale.h>
+
+
+Item* FullAdder::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new FullAdder( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* FullAdder::libraryItem()
+{
+ return new LibraryItem(
+ QString("ec/adder"),
+ i18n("Adder"),
+ i18n("Integrated Circuits"),
+ "ic1.png",
+ LibraryItem::lit_component,
+ FullAdder::construct
+ );
+}
+
+FullAdder::FullAdder( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, (id) ? id : "adder" )
+{
+ m_name = i18n("Adder");
+// m_desc = i18n("Insert missing adder help here.");
+
+ ALogic = BLogic = inLogic = 0l;
+ outLogic = SLogic = 0l;
+
+ QStringList pins = QStringList::split( ',', "A,B,>,,S,C", true );
+ initDIPSymbol( pins, 48 );
+ initDIP(pins);
+
+ ECNode *node;
+
+ node = ecNodeWithID("S");
+ SLogic = createLogicOut( node, false );
+
+ node = ecNodeWithID("C");
+ outLogic = createLogicOut( node, false );
+
+ node = ecNodeWithID("A");
+ ALogic = createLogicIn(node);
+
+ node = ecNodeWithID("B");
+ BLogic = createLogicIn(node);
+
+ node = ecNodeWithID(">");
+ inLogic = createLogicIn(node);
+
+
+ ALogic->setCallback( this, (CallbackPtr)(&FullAdder::inStateChanged) );
+ BLogic->setCallback( this, (CallbackPtr)(&FullAdder::inStateChanged) );
+ inLogic->setCallback( this, (CallbackPtr)(&FullAdder::inStateChanged) );
+}
+
+FullAdder::~FullAdder()
+{
+}
+
+
+void FullAdder::inStateChanged( bool /*state*/ )
+{
+ const bool A = ALogic->isHigh();
+ const bool B = BLogic->isHigh();
+ const bool in = inLogic->isHigh();
+
+ const bool out = (!A && B && in) || (A && !B && in) || (A && B);
+ const bool S = (!A && !B && in) || (!A && B && !in) || (A && !B && !in) || (A && B && in);
+
+ SLogic->setHigh(S);
+ outLogic->setHigh(out);
+}
+
+
diff --git a/src/electronics/components/fulladder.h b/src/electronics/components/fulladder.h
new file mode 100644
index 0000000..d4277e5
--- /dev/null
+++ b/src/electronics/components/fulladder.h
@@ -0,0 +1,37 @@
+/***************************************************************************
+ * Copyright (C) 2004 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef ECFullAdder_H
+#define ECFullAdder_H
+
+#include "component.h"
+#include "logic.h"
+
+/**
+@author David Saxton
+*/
+class FullAdder : public CallbackClass, public Component
+{
+public:
+ FullAdder( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~FullAdder();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+ virtual bool canFlip() const { return true; }
+
+protected:
+ void inStateChanged( bool newState );
+
+ LogicIn *ALogic, *BLogic, *inLogic;
+ LogicOut *outLogic, *SLogic;
+};
+
+#endif
diff --git a/src/electronics/components/inductor.cpp b/src/electronics/components/inductor.cpp
new file mode 100644
index 0000000..9e30b34
--- /dev/null
+++ b/src/electronics/components/inductor.cpp
@@ -0,0 +1,84 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "inductance.h"
+#include "inductor.h"
+#include "libraryitem.h"
+
+#include <klocale.h>
+#include <qpainter.h>
+
+Item* Inductor::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new Inductor( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* Inductor::libraryItem()
+{
+ return new LibraryItem(
+ "ec/inductor",
+ i18n("Inductor"),
+ i18n("Discrete"),
+ "inductor.png",
+ LibraryItem::lit_component,
+ Inductor::construct
+ );
+}
+
+Inductor::Inductor( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, id ? id : "inductor" )
+{
+ m_name = i18n("Inductor");
+// m_desc = i18n("Stores electrical charge.<br><br>"
+// "The voltage across the inductor and inductance are related by <i>Charge = Inductance x Voltage</i>.");
+ setSize( -16, -8, 32, 16 );
+
+ init1PinLeft();
+ init1PinRight();
+
+ m_pInductance = createInductance( m_pNNode[0], m_pPNode[0], 0.001 );
+
+ createProperty( "Inductance", Variant::Type::Double );
+ property("Inductance")->setCaption( i18n("Inductance") );
+ property("Inductance")->setUnit("H");
+ property("Inductance")->setMinValue(1e-12);
+ property("Inductance")->setMaxValue(1e12);
+ property("Inductance")->setValue(1e-3);
+
+ addDisplayText( "inductance", QRect( -8, -24, 16, 16 ), "", false );
+}
+
+Inductor::~Inductor()
+{
+}
+
+void Inductor::dataChanged()
+{
+ double inductance = dataDouble("Inductance");
+
+ QString display = QString::number( inductance / getMultiplier(inductance), 'g', 3 ) + getNumberMag(inductance) + "H";
+ setDisplayText( "inductance", display );
+
+ m_pInductance->setInductance(inductance);
+}
+
+void Inductor::drawShape( QPainter &p )
+{
+ initPainter(p);
+ int _y = int(y());
+ int _x = int(x());
+
+ p.drawArc( _x-16, _y-5, 11, 11, 0, 180*16 );
+ p.drawArc( _x-5, _y-5, 11, 11, 0, 180*16 );
+ p.drawArc( _x+6, _y-5, 11, 11, 0, 180*16 );
+
+ deinitPainter(p);
+}
+
diff --git a/src/electronics/components/inductor.h b/src/electronics/components/inductor.h
new file mode 100644
index 0000000..abb4eec
--- /dev/null
+++ b/src/electronics/components/inductor.h
@@ -0,0 +1,35 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef INDUCTOR_H
+#define INDUCTOR_H
+
+#include <component.h>
+
+/**
+@author David Saxton
+*/
+class Inductor : public Component
+{
+ public:
+ Inductor( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~Inductor();
+
+ static Item * construct( ItemDocument * itemDocument, bool newItem, const char * id );
+ static LibraryItem * libraryItem();
+
+ private:
+ void dataChanged();
+ virtual void drawShape( QPainter & p );
+
+ Inductance * m_pInductance;
+};
+
+#endif
diff --git a/src/electronics/components/magnitudecomparator.cpp b/src/electronics/components/magnitudecomparator.cpp
new file mode 100644
index 0000000..2659122
--- /dev/null
+++ b/src/electronics/components/magnitudecomparator.cpp
@@ -0,0 +1,206 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Fredy Yanardi *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "libraryitem.h"
+#include "logic.h"
+#include "magnitudecomparator.h"
+#include "variant.h"
+
+#include <cmath>
+#include <klocale.h>
+
+Item* MagnitudeComparator::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new MagnitudeComparator( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* MagnitudeComparator::libraryItem()
+{
+ return new LibraryItem(
+ QString("ec/magnitudecomparator"),
+ i18n("Magnitude Comparator"),
+ i18n("Integrated Circuits"),
+ "ic1.png",
+ LibraryItem::lit_component,
+ MagnitudeComparator::construct
+ );
+}
+
+MagnitudeComparator::MagnitudeComparator( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, id ? id : "magnitudecomparator" )
+{
+ m_name = i18n("Magnitude Comparator");
+// m_desc = i18n("Compares to two binary number and generates input to indicate which binary number has greater magnitude. It has 3 cascading inputs: I0 for I<SUB>A &gt; B</SUB>, I1 for I<SUB>A &lt; B</SUB>, and I2 for I<SUB>A = B</SUB> and 3 outputs: O0 for O<SUB>A &gt; B</SUB>, O1 for O<SUB>A &lt; B</SUB>, and O2 for O<SUB>A = B</SUB>");
+ m_desc = i18n("Compares two binary numbers and generates output to indicate which binary number has the greater magnitude. It has 3 cascading inputs:"
+ "<ul><li>I: A &gt; B</li>"
+ "<li>I: A &lt; B</li>"
+ "<li>I: A = B</li></ul>"
+ "and 3 outputs:"
+ "<ul><li>O: A &gt; B</li>"
+ "<li>O: A &lt; B</li>"
+ "<li>O: A = B</li></ul>");
+
+ createProperty( "numInput", Variant::Type::Int );
+ property("numInput")->setCaption( i18n("Number Inputs") );
+ property("numInput")->setMinValue(1);
+ property("numInput")->setMaxValue(8);
+ property("numInput")->setValue(4);
+
+ m_oldABLogicCount = 0;
+ cascadingInputs = 3;
+ outputs = 3;
+
+ firstTime = true;
+}
+
+MagnitudeComparator::~MagnitudeComparator()
+{
+}
+
+
+void MagnitudeComparator::dataChanged()
+{
+ initPins();
+}
+
+
+void MagnitudeComparator::inStateChanged()
+{
+ int i;
+
+ for ( i = 0; i < 3; i++ )
+ m_output[i]->setHigh(false);
+
+// for ( i = dataInt("numInput")-1; i >= 0; i-- ) {
+ for ( i = m_oldABLogicCount-1; i >= 0; i-- ) {
+ if (m_aLogic[i]->isHigh() && !m_bLogic[i]->isHigh())
+ {
+ m_output[0]->setHigh(true);
+ return;
+ }
+ else if ( !m_aLogic[i]->isHigh() && m_bLogic[i]->isHigh() ) {
+ m_output[1]->setHigh(true);
+ return;
+ }
+ }
+
+ if ( m_cLogic[2]->isHigh() )
+ m_output[2]->setHigh(true);
+ else if ( m_cLogic[0]->isHigh() )
+ if ( !m_cLogic[1]->isHigh() )
+ m_output[0]->setHigh(true);
+ else
+ ;
+ else if ( m_cLogic[1]->isHigh() )
+ m_output[1]->setHigh(true);
+ else {
+ m_output[0]->setHigh(true);
+ m_output[1]->setHigh(true);
+ }
+}
+
+
+void MagnitudeComparator::initPins()
+{
+ const double numInputs = dataInt("numInput");
+ int newABLogicCount = (int)numInputs;
+
+ if ( newABLogicCount == m_oldABLogicCount )
+ return;
+
+ QStringList leftPins;
+ int space = 3 - newABLogicCount;
+ for ( int i = 0; i < space; i++ )
+ leftPins << "";
+ for ( int i = 0; i < newABLogicCount; i++ )
+ leftPins << QString("A%1").arg( QString::number(i) );
+ for ( int i = 0; i < newABLogicCount; i++ )
+ leftPins << QString("B%1").arg( QString::number(i) );
+ for ( int i = 0; i < space; i++ )
+ leftPins << "";
+
+ QStringList rightPins;
+ space = -space;
+ for ( int i = 0; i < space; i++ )
+ rightPins << "";
+ QString inNames[] = { "I: A>B", "I: A<B", "I: A=B" };
+ rightPins << inNames[2] << inNames[1] << inNames[0];
+ QString outNames[] = { "O: A>B", "O: A<B", "O: A=B" };
+ rightPins << outNames[2] << outNames[1] << outNames[0];
+ for ( int i = 0; i < space; i++ )
+ rightPins << "";
+
+ QStringList pins = leftPins + rightPins;
+
+ initDIPSymbol( pins, 88 );
+ initDIP(pins);
+
+ ECNode *node;
+
+ if (firstTime) {
+ m_cLogic.resize(3);
+ for ( int i = 0; i < cascadingInputs; i++ )
+ {
+ node = ecNodeWithID( inNames[i] );
+ m_cLogic.insert( i, createLogicIn(node) );
+ m_cLogic[i]->setCallback( this, (CallbackPtr)(&MagnitudeComparator::inStateChanged));
+ }
+
+ m_output.resize(3);
+ for ( int i = 0; i < outputs; i++ )
+ {
+ node = ecNodeWithID( outNames[i] );
+ m_output.insert( i, createLogicOut(node,false) );
+ }
+ firstTime = false;
+ }
+
+ if ( newABLogicCount > m_oldABLogicCount )
+ {
+ m_aLogic.resize(newABLogicCount);
+ for ( int i=m_oldABLogicCount; i<newABLogicCount; ++i )
+ {
+ node = ecNodeWithID("A"+QString::number(i));
+ m_aLogic.insert( i, createLogicIn(node) );
+ m_aLogic[i]->setCallback( this, (CallbackPtr)(&MagnitudeComparator::inStateChanged) );
+ }
+
+ m_bLogic.resize(newABLogicCount);
+ for ( int i=m_oldABLogicCount; i<newABLogicCount; ++i )
+ {
+ node = ecNodeWithID("B"+QString::number(i));
+ m_bLogic.insert( i, createLogicIn(node) );
+ m_bLogic[i]->setCallback( this, (CallbackPtr)(&MagnitudeComparator::inStateChanged) );
+ }
+ }
+ else
+ {
+ for ( int i=newABLogicCount; i<m_oldABLogicCount; ++i )
+ {
+ QString id = "A"+QString::number(i);
+ removeDisplayText(id);
+ removeElement( m_aLogic[i], false );
+ removeNode(id);
+ }
+ m_aLogic.resize(newABLogicCount);
+ for ( int i=newABLogicCount; i<m_oldABLogicCount; ++i )
+ {
+ QString id = "B"+QString::number(i);
+ removeDisplayText(id);
+ removeElement( m_bLogic[i], false );
+ removeNode(id);
+ }
+ m_bLogic.resize(newABLogicCount);
+ }
+
+ m_oldABLogicCount = newABLogicCount;
+ inStateChanged();
+}
+
+
diff --git a/src/electronics/components/magnitudecomparator.h b/src/electronics/components/magnitudecomparator.h
new file mode 100644
index 0000000..57dc748
--- /dev/null
+++ b/src/electronics/components/magnitudecomparator.h
@@ -0,0 +1,50 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Fredy Yanardi *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef MAGNITUDECOMPARATOR_H
+#define MAGNITUDECOMPARATOR_H
+
+#include "component.h"
+#include "logic.h"
+
+#include <qbitarray.h>
+#include <qptrvector.h>
+
+/**
+@author Fredy Yanardi
+ */
+class MagnitudeComparator : public CallbackClass, public Component
+{
+ public:
+ MagnitudeComparator( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~MagnitudeComparator();
+
+ virtual bool canFlip() const { return true; }
+ static Item * construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem * libraryItem();
+
+ protected:
+ void initPins();
+ virtual void dataChanged();
+ void inStateChanged();
+
+ int m_oldABLogicCount;
+ int cascadingInputs;
+ int outputs;
+ bool firstTime;
+
+ QBitArray m_data;
+
+ QPtrVector<LogicIn> m_aLogic;
+ QPtrVector<LogicIn> m_bLogic;
+ QPtrVector<LogicIn> m_cLogic;
+ QPtrVector<LogicOut> m_output;
+};
+
+#endif
diff --git a/src/electronics/components/matrixdisplay.cpp b/src/electronics/components/matrixdisplay.cpp
new file mode 100644
index 0000000..dd40b6a
--- /dev/null
+++ b/src/electronics/components/matrixdisplay.cpp
@@ -0,0 +1,291 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "colorcombo.h"
+#include "diode.h"
+#include "ecled.h"
+#include "ecnode.h"
+#include "libraryitem.h"
+#include "matrixdisplay.h"
+#include "simulator.h"
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <qpainter.h>
+#include <qstring.h>
+
+Item* MatrixDisplay::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new MatrixDisplay( (ICNDocument*)itemDocument, newItem, id );
+}
+
+
+LibraryItem* MatrixDisplay::libraryItem()
+{
+ return new LibraryItem(
+ "ec/matrix_display",
+ i18n("Matrix Display"),
+ i18n("Outputs"),
+ "matrixdisplay.png",
+ LibraryItem::lit_component,
+ MatrixDisplay::construct );
+}
+
+
+MatrixDisplay::MatrixDisplay( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, id ? id : "matrix_display" )
+{
+ m_name = i18n("Matrix Display");
+ m_desc = i18n("A matrix display of LEDs with a configurable number of columns and rows.");
+ m_bDynamicContent = true;
+
+ //BEGIN Reset members
+ for ( unsigned i = 0; i < max_md_height; i++ )
+ m_pRowNodes[i] = 0l;
+ for ( unsigned i = 0; i < max_md_width; i++ )
+ m_pColNodes[i] = 0l;
+
+ m_lastUpdatePeriod = 0.0;
+ m_r = m_g = m_b = 0.0;
+ m_bRowCathode = true;
+ m_numRows = 0;
+ m_numCols = 0;
+ //END Reset members
+
+ createProperty( "0-rows", Variant::Type::Int );
+ property("0-rows")->setCaption( i18n("Rows") );
+ property("0-rows")->setMinValue(1);
+ property("0-rows")->setMaxValue(max_md_height);
+ property("0-rows")->setValue(7);
+
+ createProperty( "1-cols", Variant::Type::Int );
+ property("1-cols")->setCaption( i18n("Columns") );
+ property("1-cols")->setMinValue(1);
+ property("1-cols")->setMaxValue(max_md_width);
+ property("1-cols")->setValue(5);
+
+ createProperty( "color", Variant::Type::Color );
+ property("color")->setCaption( i18n("Color") );
+ property("color")->setColorScheme( ColorCombo::LED );
+
+ createProperty( "diode-configuration", Variant::Type::Select );
+ property("diode-configuration")->setCaption( i18n("Configuration") );
+ property("diode-configuration")->setAllowed( QStringList::split(',',"Row Cathode,Column Cathode") );
+ property("diode-configuration")->setValue("Row Cathode");
+ property("diode-configuration")->setAdvanced(true);
+}
+
+
+MatrixDisplay::~MatrixDisplay()
+{
+}
+
+
+void MatrixDisplay::dataChanged()
+{
+ QColor color = dataColor("color");
+ m_r = double(color.red()) / double(0x100);
+ m_g = double(color.green()) / double(0x100);
+ m_b = double(color.blue()) / double(0x100);
+
+ int numRows = dataInt("0-rows");
+ int numCols = dataInt("1-cols");
+
+ bool ledsChanged = (numRows != int(m_numRows)) || (numCols != int(m_numCols));
+
+ if (ledsChanged)
+ initPins( numRows, numCols );
+
+ bool rowCathode = dataString("diode-configuration") == "Row Cathode";
+ if ( (rowCathode != m_bRowCathode) || ledsChanged)
+ {
+ m_bRowCathode = rowCathode;
+
+ for ( unsigned i = 0; i < m_numCols; i++ )
+ {
+ for ( unsigned j = 0; j < m_numRows; j++ )
+ {
+ removeElement( m_pDiodes[i][j], false );
+ if (rowCathode)
+ m_pDiodes[i][j] = createDiode( m_pColNodes[i], m_pRowNodes[j] );
+ else
+ m_pDiodes[i][j] = createDiode( m_pRowNodes[j], m_pColNodes[i] );
+ }
+ }
+ }
+}
+
+
+void MatrixDisplay::initPins( unsigned numRows, unsigned numCols )
+{
+ if ( (numRows == m_numRows) && (numCols == m_numCols) )
+ return;
+
+ if ( numRows > max_md_height )
+ numRows = max_md_height;
+
+ if ( numCols > max_md_width )
+ numCols = max_md_width;
+
+ m_lastUpdatePeriod = 0.0;
+
+ //BEGIN Remove diodes
+ // All the diodes are going to be readded from dataChanged (where this
+ // function is called from), so easiest just to delete the diodes now and
+ // resize.
+
+ for ( unsigned i = 0; i < m_numCols; i++ )
+ {
+ for ( unsigned j = 0; j < m_numRows; j++ )
+ removeElement( m_pDiodes[i][j], false );
+ }
+
+ m_avgBrightness.resize(numCols);
+ m_lastBrightness.resize(numCols);
+ m_pDiodes.resize(numCols);
+
+ for ( unsigned i = 0; i < numCols; i++ )
+ {
+ m_avgBrightness[i].resize(numRows);
+ m_lastBrightness[i].resize(numRows);
+ m_pDiodes[i].resize(numRows);
+
+ for ( unsigned j = 0; j < numRows; j++ )
+ {
+ m_avgBrightness[i][j] = 0.0;
+ m_lastBrightness[i][j] = 255;
+ m_pDiodes[i][j] = 0l;
+ }
+
+ }
+ //END Remove diodes
+
+
+ //BEGIN Create or destroy pins
+ if ( numCols >= m_numCols )
+ {
+ for ( unsigned i = m_numCols; i < numCols; i++ )
+ m_pColNodes[i] = createPin( 0, 0, 270, colPinID(i) );
+ }
+ else
+ {
+ for ( unsigned i = numCols; i < m_numCols; i++ )
+ {
+ removeNode( colPinID(i) );
+ m_pColNodes[i] = 0l;
+ }
+ }
+ m_numCols = numCols;
+
+ if ( numRows >= m_numRows )
+ {
+ for ( unsigned i = m_numRows; i < numRows; i++ )
+ m_pRowNodes[i] = createPin( 0, 0, 0, rowPinID(i) );
+ }
+ else
+ {
+ for ( unsigned i = numRows; i < m_numRows; i++ )
+ {
+ removeNode( rowPinID(i) );
+ m_pRowNodes[i] = 0l;
+ }
+ }
+ m_numRows = numRows;
+ //END Create or destroy pins
+
+
+ //BEGIN Position pins et al
+ setSize( -int(numCols+1)*8, -int(numRows+1)*8, int(numCols+1)*16, int(numRows+1)*16, true );
+
+ for ( int i = 0; i < int(m_numCols); i++ )
+ {
+ m_nodeMap[colPinID(i)].x = offsetX() + 16 + 16*i;
+ m_nodeMap[colPinID(i)].y = offsetY() + height() + 8;
+ }
+
+ for ( int i = 0; i < int(m_numRows); i++ )
+ {
+ m_nodeMap[rowPinID(i)].x = offsetX() - 8;
+ m_nodeMap[rowPinID(i)].y = offsetY() + 16 + 16*i;
+ }
+
+ updateAttachedPositioning();
+ //END Position pins et al
+}
+
+
+QString MatrixDisplay::colPinID( int col ) const
+{
+ return QString("col_%1").arg(QString::number(col));
+}
+QString MatrixDisplay::rowPinID( int row ) const
+{
+ return QString("row_%1").arg(QString::number(row));
+}
+
+
+void MatrixDisplay::stepNonLogic()
+{
+ double interval = 1./LINEAR_UPDATE_RATE;
+
+ for ( unsigned i = 0; i < m_numCols; i++ )
+ {
+ for ( unsigned j = 0; j < m_numRows; j++ )
+ m_avgBrightness[i][j] += ECLed::brightness( m_pDiodes[i][j]->current() )*interval;
+ }
+
+ m_lastUpdatePeriod += interval;
+}
+
+
+void MatrixDisplay::drawShape( QPainter &p )
+{
+ if ( isSelected() )
+ p.setPen(m_selectedCol);
+ p.drawRect( boundingRect() );
+
+ initPainter(p);
+
+ const int _x = int(x()+offsetX());
+ const int _y = int(y()+offsetY());
+
+ // To avoid flicker, require at least a 10 ms sample before changing
+ // the brightness
+ double minUpdatePeriod = 0.0099;
+
+ for ( int i = 0; i < int(m_numCols); i++ )
+ {
+ for ( int j = 0; j < int(m_numRows); j++ )
+ {
+ if ( m_lastUpdatePeriod > minUpdatePeriod )
+ m_lastBrightness[i][j] = unsigned(m_avgBrightness[i][j]/m_lastUpdatePeriod);
+
+ double _b = m_lastBrightness[i][j];
+
+ QColor brush = QColor( uint(255-(255-_b)*(1-m_r)), uint(255-(255-_b)*(1-m_g)), uint(255-(255-_b)*(1-m_b)) );
+ p.setBrush(brush);
+ p.setPen( Qt::NoPen );
+ p.drawEllipse( _x+10+i*16, _y+10+j*16, 12, 12 );
+ }
+ }
+
+ if ( m_lastUpdatePeriod > minUpdatePeriod )
+ {
+ m_lastUpdatePeriod = 0.0;
+
+ for ( unsigned i = 0; i < m_numCols; i++ )
+ {
+ for ( unsigned j = 0; j < m_numRows; j++ )
+ m_avgBrightness[i][j] = 0.0;
+ }
+ }
+
+ deinitPainter(p);
+}
diff --git a/src/electronics/components/matrixdisplay.h b/src/electronics/components/matrixdisplay.h
new file mode 100644
index 0000000..4851817
--- /dev/null
+++ b/src/electronics/components/matrixdisplay.h
@@ -0,0 +1,60 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef MATRIXDISPLAY_H
+#define MATRIXDISPLAY_H
+
+#include <component.h>
+#include <qvaluevector.h>
+
+const unsigned max_md_width = 100;
+const unsigned max_md_height = 20;
+
+/**
+@author David Saxton
+*/
+class MatrixDisplay : public Component
+{
+ public:
+ MatrixDisplay( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~MatrixDisplay();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+ virtual bool canFlip() const { return true; }
+ virtual void stepNonLogic();
+ virtual bool doesStepNonLogic() const { return true; }
+
+ protected:
+ virtual void drawShape( QPainter &p );
+ virtual void dataChanged();
+ void initPins( unsigned numRows, unsigned numCols );
+ QString colPinID( int col ) const;
+ QString rowPinID( int row ) const;
+
+
+ QValueVector< QValueVector<double> > m_avgBrightness;
+ QValueVector< QValueVector<unsigned> > m_lastBrightness;
+ QValueVector< QValueVector<Diode*> > m_pDiodes;
+
+ ECNode * m_pRowNodes[max_md_height];
+ ECNode * m_pColNodes[max_md_width];
+
+ double m_lastUpdatePeriod;
+
+ double m_r, m_g, m_b;
+ bool m_bRowCathode;
+
+ unsigned m_numRows;
+ unsigned m_numCols;
+};
+
+#endif
diff --git a/src/electronics/components/matrixdisplaydriver.cpp b/src/electronics/components/matrixdisplaydriver.cpp
new file mode 100644
index 0000000..da00bb7
--- /dev/null
+++ b/src/electronics/components/matrixdisplaydriver.cpp
@@ -0,0 +1,380 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "libraryitem.h"
+#include "logic.h"
+#include "matrixdisplaydriver.h"
+
+#include <klocale.h>
+#include <qpainter.h>
+#include <qstring.h>
+
+#include <assert.h>
+
+// Thank you Scott Dattalo!
+// http://www.dattalo.com/gnupic/lcdfont.inc
+
+static char characterMap[256][5] = {
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //0
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //1
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //2
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //3
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //4
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //5
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //6
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //7
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //8
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //9
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //10
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //11
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //12
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //13
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //14
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //15
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //16
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //17
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //18
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //19
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //20
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //21
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //22
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //23
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //24
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //25
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //26
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //27
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //28
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //29
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //30
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //31
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //32
+{ 0x00, 0x00, 0x7d, 0x00, 0x00 }, //33
+{ 0x00, 0x70, 0x00, 0x70, 0x00 }, //34
+{ 0x14, 0x7f, 0x14, 0x7f, 0x14 }, //35
+{ 0x12, 0x2a, 0x7f, 0x2a, 0x24 }, //36
+{ 0x62, 0x64, 0x08, 0x13, 0x23 }, //37
+{ 0x36, 0x49, 0x55, 0x22, 0x05 }, //38
+{ 0x00, 0x50, 0x60, 0x00, 0x00 }, //39
+{ 0x00, 0x1c, 0x22, 0x41, 0x00 }, //40
+{ 0x00, 0x41, 0x22, 0x1c, 0x00 }, //41
+{ 0x14, 0x08, 0x3e, 0x08, 0x14 }, //42
+{ 0x08, 0x08, 0x3e, 0x08, 0x08 }, //43
+{ 0x00, 0x05, 0x06, 0x00, 0x00 }, //44
+{ 0x08, 0x08, 0x08, 0x08, 0x08 }, //45
+{ 0x00, 0x03, 0x03, 0x00, 0x00 }, //46
+{ 0x02, 0x04, 0x08, 0x10, 0x20 }, //47
+{ 0x3e, 0x45, 0x49, 0x51, 0x3e }, //48
+{ 0x00, 0x21, 0x7f, 0x01, 0x00 }, //49
+{ 0x21, 0x43, 0x45, 0x49, 0x31 }, //50
+{ 0x42, 0x41, 0x51, 0x69, 0x46 }, //51
+{ 0x0c, 0x14, 0x24, 0x7f, 0x04 }, //52
+{ 0x72, 0x51, 0x51, 0x51, 0x4e }, //53
+{ 0x1e, 0x29, 0x49, 0x49, 0x06 }, //54
+{ 0x40, 0x47, 0x48, 0x50, 0x60 }, //55
+{ 0x36, 0x49, 0x49, 0x49, 0x36 }, //56
+{ 0x30, 0x49, 0x49, 0x4a, 0x3c }, //57
+{ 0x00, 0x36, 0x36, 0x00, 0x00 }, //58
+{ 0x00, 0x35, 0x36, 0x00, 0x00 }, //59
+{ 0x08, 0x14, 0x22, 0x41, 0x00 }, //60
+{ 0x14, 0x14, 0x14, 0x14, 0x14 }, //61
+{ 0x41, 0x22, 0x14, 0x08, 0x00 }, //62
+{ 0x20, 0x40, 0x45, 0x48, 0x30 }, //63
+{ 0x26, 0x49, 0x4f, 0x41, 0x3e }, //64
+{ 0x3f, 0x44, 0x44, 0x44, 0x3f }, //65
+{ 0x7f, 0x49, 0x49, 0x49, 0x36 }, //66
+{ 0x3e, 0x41, 0x41, 0x41, 0x22 }, //67
+{ 0x7f, 0x41, 0x41, 0x41, 0x3e }, //68
+{ 0x7f, 0x49, 0x49, 0x49, 0x41 }, //69
+{ 0x7f, 0x48, 0x48, 0x48, 0x40 }, //70
+{ 0x3e, 0x41, 0x49, 0x49, 0x2f }, //71
+{ 0x7f, 0x08, 0x08, 0x08, 0x7f }, //72
+{ 0x00, 0x41, 0x7f, 0x41, 0x00 }, //73
+{ 0x02, 0x01, 0x41, 0x7e, 0x40 }, //74
+{ 0x7f, 0x08, 0x14, 0x22, 0x41 }, //75
+{ 0x7f, 0x01, 0x01, 0x01, 0x01 }, //76
+{ 0x7f, 0x40, 0x20, 0x40, 0x7f }, //77
+{ 0x7f, 0x10, 0x08, 0x04, 0x7f }, //78
+{ 0x3e, 0x41, 0x41, 0x41, 0x3e }, //79
+{ 0x7f, 0x48, 0x48, 0x48, 0x30 }, //80
+{ 0x3e, 0x41, 0x45, 0x42, 0x3d }, //81
+{ 0x7f, 0x48, 0x4c, 0x4a, 0x31 }, //82
+{ 0x31, 0x49, 0x49, 0x49, 0x46 }, //83
+{ 0x40, 0x40, 0x7f, 0x40, 0x40 }, //84
+{ 0x7e, 0x01, 0x01, 0x01, 0x7e }, //85
+{ 0x7c, 0x02, 0x01, 0x02, 0x7c }, //86
+{ 0x7e, 0x01, 0x0e, 0x01, 0x7e }, //87
+{ 0x63, 0x14, 0x08, 0x14, 0x63 }, //88
+{ 0x70, 0x08, 0x07, 0x08, 0x70 }, //89
+{ 0x43, 0x45, 0x49, 0x51, 0x61 }, //90
+{ 0x00, 0x7f, 0x41, 0x41, 0x00 }, //91
+{ 0x54, 0x34, 0x1f, 0x34, 0x54 }, //92
+{ 0x00, 0x41, 0x41, 0x7f, 0x00 }, //93
+{ 0x10, 0x20, 0x40, 0x20, 0x10 }, //94
+{ 0x01, 0x01, 0x01, 0x01, 0x01 }, //95
+{ 0x00, 0x40, 0x20, 0x10, 0x00 }, //96
+{ 0x02, 0x15, 0x15, 0x15, 0x0f }, //97
+{ 0x7f, 0x09, 0x11, 0x11, 0x0e }, //98
+{ 0x0e, 0x11, 0x11, 0x11, 0x02 }, //99
+{ 0x0e, 0x11, 0x11, 0x09, 0x7f }, //100
+{ 0x0e, 0x15, 0x15, 0x15, 0x0c }, //101
+{ 0x08, 0x3f, 0x48, 0x40, 0x20 }, //102
+{ 0x30, 0x49, 0x49, 0x49, 0x7e }, //103
+{ 0x7f, 0x08, 0x10, 0x10, 0x0f }, //104
+{ 0x00, 0x11, 0x5f, 0x01, 0x00 }, //105
+{ 0x02, 0x01, 0x21, 0x7e, 0x00 }, //106
+{ 0x7f, 0x04, 0x0a, 0x11, 0x00 }, //107
+{ 0x00, 0x41, 0x7f, 0x01, 0x00 }, //108
+{ 0x1f, 0x10, 0x0c, 0x10, 0x0f }, //109
+{ 0x1f, 0x08, 0x10, 0x10, 0x0f }, //110
+{ 0x0e, 0x11, 0x11, 0x11, 0x0e }, //111
+{ 0x1f, 0x14, 0x14, 0x14, 0x08 }, //112
+{ 0x08, 0x14, 0x14, 0x0c, 0x1f }, //113
+{ 0x1f, 0x08, 0x10, 0x10, 0x08 }, //114
+{ 0x09, 0x15, 0x15, 0x15, 0x12 }, //115
+{ 0x20, 0x7e, 0x21, 0x01, 0x02 }, //116
+{ 0x1e, 0x01, 0x01, 0x02, 0x1f }, //117
+{ 0x1c, 0x02, 0x01, 0x02, 0x1c }, //118
+{ 0x1e, 0x01, 0x06, 0x01, 0x1e }, //119
+{ 0x11, 0x0a, 0x04, 0x0a, 0x11 }, //120
+{ 0x18, 0x05, 0x05, 0x05, 0x1e }, //121
+{ 0x11, 0x13, 0x15, 0x19, 0x11 }, //122
+{ 0x00, 0x08, 0x36, 0x41, 0x00 }, //123
+{ 0x00, 0x00, 0x7f, 0x00, 0x00 }, //124
+{ 0x00, 0x41, 0x36, 0x08, 0x00 }, //125
+{ 0x08, 0x08, 0x2a, 0x1c, 0x08 }, //126
+{ 0x08, 0x1c, 0x2a, 0x08, 0x08 }, //127
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //128
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //129
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //130
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //131
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //132
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //133
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //134
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //135
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //136
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //137
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //138
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //139
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //140
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //141
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //142
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //143
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //144
+{ 0x07, 0x05, 0x07, 0x00, 0x00 }, //145
+{ 0x00, 0x00, 0x78, 0x40, 0x40 }, //146
+{ 0x01, 0x01, 0x0f, 0x00, 0x00 }, //147
+{ 0x04, 0x02, 0x01, 0x00, 0x00 }, //148
+{ 0x00, 0x0c, 0x0c, 0x00, 0x00 }, //149
+{ 0x28, 0x28, 0x29, 0x2a, 0x3c }, //150
+{ 0x10, 0x11, 0x16, 0x14, 0x18 }, //151
+{ 0x02, 0x04, 0x0f, 0x10, 0x00 }, //152
+{ 0x0c, 0x08, 0x19, 0x09, 0x0e }, //153
+{ 0x09, 0x09, 0x0f, 0x09, 0x09 }, //154
+{ 0x09, 0x0a, 0x0c, 0x1f, 0x08 }, //155
+{ 0x08, 0x1f, 0x08, 0x0a, 0x0c }, //156
+{ 0x01, 0x09, 0x09, 0x0f, 0x01 }, //157
+{ 0x15, 0x15, 0x15, 0x1f, 0x00 }, //158
+{ 0x0c, 0x00, 0x0d, 0x01, 0x0e }, //159
+{ 0x04, 0x04, 0x04, 0x04, 0x04 }, //160
+{ 0x40, 0x41, 0x5e, 0x48, 0x70 }, //161
+{ 0x04, 0x08, 0x1f, 0x20, 0x40 }, //162
+{ 0x38, 0x20, 0x61, 0x22, 0x3c }, //163
+{ 0x11, 0x11, 0x1f, 0x11, 0x11 }, //164
+{ 0x22, 0x24, 0x28, 0x7f, 0x20 }, //165
+{ 0x21, 0x7e, 0x20, 0x21, 0x3e }, //166
+{ 0x28, 0x28, 0x7f, 0x28, 0x28 }, //167
+{ 0x08, 0x31, 0x21, 0x22, 0x3c }, //168
+{ 0x10, 0x60, 0x21, 0x3e, 0x20 }, //169
+{ 0x21, 0x21, 0x21, 0x21, 0x3f }, //170
+{ 0x20, 0x79, 0x22, 0x7c, 0x20 }, //171
+{ 0x29, 0x29, 0x01, 0x02, 0x1c }, //172
+{ 0x21, 0x22, 0x24, 0x2a, 0x31 }, //173
+{ 0x20, 0x7e, 0x21, 0x29, 0x31 }, //174
+{ 0x30, 0x09, 0x01, 0x02, 0x3c }, //175
+{ 0x08, 0x31, 0x29, 0x26, 0x3c }, //176
+{ 0x28, 0x29, 0x3e, 0x48, 0x08 }, //177
+{ 0x30, 0x00, 0x31, 0x02, 0x3c }, //178
+{ 0x10, 0x51, 0x5e, 0x50, 0x10 }, //179
+{ 0x00, 0x7f, 0x08, 0x04, 0x00 }, //180
+{ 0x11, 0x12, 0x7c, 0x10, 0x10 }, //181
+{ 0x01, 0x21, 0x21, 0x21, 0x01 }, //182
+{ 0x21, 0x2a, 0x24, 0x2a, 0x30 }, //183
+{ 0x22, 0x24, 0x6f, 0x34, 0x22 }, //184
+{ 0x00, 0x01, 0x02, 0x7c, 0x00 }, //185
+{ 0x0f, 0x00, 0x20, 0x10, 0x0f }, //186
+{ 0x7e, 0x11, 0x11, 0x11, 0x11 }, //187
+{ 0x20, 0x21, 0x21, 0x22, 0x3c }, //188
+{ 0x10, 0x20, 0x10, 0x08, 0x06 }, //189
+{ 0x26, 0x20, 0x7f, 0x20, 0x26 }, //190
+{ 0x20, 0x24, 0x22, 0x25, 0x38 }, //191
+{ 0x00, 0x2a, 0x2a, 0x2a, 0x01 }, //192
+{ 0x0e, 0x12, 0x22, 0x02, 0x07 }, //193
+{ 0x01, 0x0a, 0x04, 0x0a, 0x30 }, //194
+{ 0x28, 0x3e, 0x29, 0x29, 0x29 }, //195
+{ 0x10, 0x7f, 0x10, 0x14, 0x18 }, //196
+{ 0x01, 0x21, 0x21, 0x3f, 0x01 }, //197
+{ 0x29, 0x29, 0x29, 0x29, 0x3f }, //198
+{ 0x10, 0x50, 0x51, 0x52, 0x1c }, //199
+{ 0x78, 0x01, 0x02, 0x7c, 0x00 }, //200
+{ 0x1f, 0x00, 0x3f, 0x01, 0x06 }, //201
+{ 0x3f, 0x01, 0x02, 0x04, 0x08 }, //202
+{ 0x3f, 0x21, 0x21, 0x21, 0x3f }, //203
+{ 0x38, 0x20, 0x21, 0x22, 0x3c }, //204
+{ 0x21, 0x21, 0x01, 0x02, 0x0c }, //205
+{ 0x20, 0x10, 0x40, 0x20, 0x00 }, //206
+{ 0x70, 0x50, 0x70, 0x00, 0x00 }, //207
+{ 0x0e, 0x11, 0x09, 0x06, 0x19 }, //208
+{ 0x02, 0x55, 0x15, 0x55, 0x0f }, //209
+{ 0x1f, 0x2a, 0x2a, 0x2a, 0x14 }, //210
+{ 0x0a, 0x15, 0x15, 0x11, 0x02 }, //211
+{ 0x3f, 0x02, 0x02, 0x04, 0x3e }, //212
+{ 0x0e, 0x11, 0x19, 0x15, 0x12 }, //213
+{ 0x0f, 0x12, 0x22, 0x22, 0x1c }, //214
+{ 0x1c, 0x22, 0x22, 0x22, 0x3f }, //215
+{ 0x02, 0x01, 0x1e, 0x10, 0x10 }, //216
+{ 0x20, 0x20, 0x00, 0x70, 0x00 }, //217
+{ 0x00, 0x00, 0x10, 0x5f, 0x00 }, //218
+{ 0x28, 0x10, 0x28, 0x00, 0x00 }, //219
+{ 0x18, 0x24, 0x7e, 0x24, 0x08 }, //220
+{ 0x14, 0x7f, 0x15, 0x01, 0x01 }, //221
+{ 0x1f, 0x48, 0x50, 0x50, 0x0f }, //222
+{ 0x0e, 0x51, 0x11, 0x51, 0x0e }, //223
+{ 0x3f, 0x12, 0x22, 0x22, 0x1c }, //224
+{ 0x1c, 0x22, 0x22, 0x12, 0x3f }, //225
+{ 0x3c, 0x52, 0x52, 0x52, 0x3c }, //226
+{ 0x03, 0x05, 0x02, 0x05, 0x06 }, //227
+{ 0x1a, 0x26, 0x20, 0x26, 0x1a }, //228
+{ 0x1e, 0x41, 0x01, 0x42, 0x1f }, //229
+{ 0x63, 0x55, 0x49, 0x41, 0x41 }, //230
+{ 0x22, 0x3c, 0x20, 0x3e, 0x22 }, //231
+{ 0x51, 0x4a, 0x44, 0x4a, 0x51 }, //232
+{ 0x3c, 0x02, 0x02, 0x02, 0x3f }, //233
+{ 0x28, 0x28, 0x3e, 0x28, 0x48 }, //234
+{ 0x22, 0x3c, 0x28, 0x28, 0x2e }, //235
+{ 0x3e, 0x28, 0x38, 0x28, 0x3e }, //236
+{ 0x04, 0x04, 0x15, 0x04, 0x04 }, //237
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //238
+{ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f }, //239
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //240
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //241
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //242
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //243
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //244
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //245
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //246
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //247
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //248
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //249
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //250
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //251
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //252
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //253
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //254
+{ 0x00, 0x00, 0x00, 0x00, 0x00 }, //255
+ };
+
+
+inline static bool displayBit( unsigned value, unsigned row, unsigned column )
+{
+ assert( value < 256 );
+ assert( row < 7 );
+ assert( column < 5 );
+ return characterMap[value][column] & (1 << row);
+};
+
+
+Item* MatrixDisplayDriver::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new MatrixDisplayDriver( (ICNDocument*)itemDocument, newItem, id );
+}
+
+
+LibraryItem * MatrixDisplayDriver::libraryItem()
+{
+ return new LibraryItem(
+ "ec/matrix_display_driver",
+ i18n("Matrix Display Driver"),
+ i18n("Integrated Circuits"),
+ "ic2.png",
+ LibraryItem::lit_component,
+ MatrixDisplayDriver::construct );
+}
+
+
+MatrixDisplayDriver::MatrixDisplayDriver( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, id ? id : "Matrix Display Driver" )
+{
+ m_name = i18n("Matrix Display Driver");
+
+ m_prevCol = 0;
+ m_nextCol = 0;
+ m_scanCount = 2;
+
+ createProperty( "diode-configuration", Variant::Type::Select );
+ property("diode-configuration")->setCaption( i18n("Configuration") );
+ property("diode-configuration")->setAllowed( QStringList::split(',',"Row Cathode,Column Cathode") );
+ property("diode-configuration")->setValue("Row Cathode");
+ property("diode-configuration")->setAdvanced(true);
+
+ QStringList pins = QStringList::split( ',', "D0,D1,D2,D3,D4,D5,D6,D7,,,,,,C4,C3,C2,C1,C0,,R0,R1,R2,R3,R4,R5,R6", true );
+ initDIPSymbol( pins, 64 );
+ initDIP(pins);
+
+ m_pValueLogic.resize( 8, 0l );
+ for ( unsigned i = 0; i < 8; ++i )
+ m_pValueLogic[i] = createLogicIn( ecNodeWithID("D"+QString::number(i)) );
+
+ m_pRowLogic.resize( 7, 0l );
+ for ( unsigned i = 0; i < 7; ++i )
+ {
+ m_pRowLogic[i] = createLogicOut( ecNodeWithID("R"+QString::number(i)), false );
+ m_pRowLogic[i]->setOutputLowConductance( 1.0 );
+ m_pRowLogic[i]->setOutputHighVoltage(5.0);
+ }
+
+ m_pColLogic.resize( 5, 0l );
+ for ( unsigned i = 0; i < 5; ++i )
+ {
+ m_pColLogic[i] = createLogicOut( ecNodeWithID("C"+QString::number(i)), false );
+ m_pColLogic[i]->setOutputHighVoltage(5.0);
+ }
+}
+
+
+MatrixDisplayDriver::~MatrixDisplayDriver()
+{
+}
+
+
+void MatrixDisplayDriver::stepNonLogic()
+{
+ if ( ++m_scanCount < 5 )
+ return;
+ m_scanCount = 0;
+
+ m_pColLogic[m_prevCol]->setHigh(false);
+ m_pColLogic[m_nextCol]->setHigh(true);
+
+ unsigned value = 0;
+ for ( unsigned i = 0; i < 8; ++i )
+ value |= ( m_pValueLogic[i]->isHigh() ) ? (1 << i) : 0;
+
+ for ( unsigned row = 0; row < 7; row++ )
+ {
+ m_pRowLogic[row]->setHigh( !displayBit( value, row, m_nextCol) );
+ }
+
+ m_prevCol = m_nextCol;
+
+ m_nextCol++;
+ if ( m_nextCol >= 5 )
+ m_nextCol = 0;
+}
+
diff --git a/src/electronics/components/matrixdisplaydriver.h b/src/electronics/components/matrixdisplaydriver.h
new file mode 100644
index 0000000..e6b01cc
--- /dev/null
+++ b/src/electronics/components/matrixdisplaydriver.h
@@ -0,0 +1,42 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef MATRIXDISPLAYDRIVER_H
+#define MATRIXDISPLAYDRIVER_H
+
+#include "matrixdisplay.h"
+
+/**
+@author David Saxton
+ */
+class MatrixDisplayDriver : public Component
+{
+ public:
+ MatrixDisplayDriver( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~MatrixDisplayDriver();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+ virtual bool canFlip() const { return true; }
+ virtual void stepNonLogic();
+ virtual bool doesStepNonLogic() const { return true; }
+
+ protected:
+ QValueVector<LogicIn*> m_pValueLogic;
+ QValueVector<LogicOut*> m_pRowLogic;
+ QValueVector<LogicOut*> m_pColLogic;
+
+ unsigned m_prevCol;
+ unsigned m_nextCol;
+ unsigned m_scanCount;
+};
+
+#endif
diff --git a/src/electronics/components/meter.cpp b/src/electronics/components/meter.cpp
new file mode 100644
index 0000000..4437794
--- /dev/null
+++ b/src/electronics/components/meter.cpp
@@ -0,0 +1,265 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "canvasitemparts.h"
+#include "ecnode.h"
+#include "element.h"
+#include "libraryitem.h"
+#include "meter.h"
+#include "variant.h"
+#include "voltagesource.h"
+#include "pin.h"
+#include "simulator.h"
+
+#include <cmath>
+#include <klocale.h>
+#include <qpainter.h>
+
+
+//BEGIN class Meter
+Meter::Meter( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, id )
+{
+ m_bDynamicContent = true;
+ b_timerStarted = false;
+ m_timeSinceUpdate = 0.;
+ m_old_value = 0.;
+ m_avgValue = 0.;
+ b_firstRun = true;
+ setSize( -16, -16, 32, 32 );
+
+ p_displayText = addDisplayText( "meter", QRect( -16, 16, 32, 16 ), displayText() );
+
+ createProperty( "0-minValue", Variant::Type::Double );
+ property("0-minValue")->setCaption( i18n("Minimum Value") );
+ property("0-minValue")->setMinValue(1e-12);
+ property("0-minValue")->setMaxValue(1e12);
+ property("0-minValue")->setValue(1e-3);
+
+ createProperty( "1-maxValue", Variant::Type::Double );
+ property("1-maxValue")->setCaption( i18n("Maximum Value") );
+ property("1-maxValue")->setMinValue(1e-12);
+ property("1-maxValue")->setMaxValue(1e12);
+ property("1-maxValue")->setValue(1e3);
+}
+
+
+Meter::~Meter()
+{
+}
+
+
+void Meter::dataChanged()
+{
+ m_minValue = dataDouble("0-minValue");
+ m_maxValue = dataDouble("1-maxValue");
+ setChanged();
+}
+
+void Meter::stepNonLogic()
+{
+ if (b_firstRun)
+ {
+ p_displayText->setText(displayText());
+ updateAttachedPositioning();
+ setChanged();
+ property("0-minValue")->setUnit(m_unit);
+ property("1-maxValue")->setUnit(m_unit);
+ b_firstRun = false;
+ }
+
+ const double v = meterValue();
+ if ( !b_timerStarted && std::abs(((v-m_old_value)/m_old_value)) > 1e-6 ) {
+ b_timerStarted = true;
+ }
+
+ if (b_timerStarted)
+ {
+ m_timeSinceUpdate += 1./LINEAR_UPDATE_RATE;
+ m_avgValue += v/LINEAR_UPDATE_RATE;
+// setChanged();
+ if ( m_timeSinceUpdate > 0.05 )
+ {
+ if ( p_displayText->setText(displayText()) );
+ updateAttachedPositioning();
+ }
+ }
+}
+
+void Meter::drawShape( QPainter &p )
+{
+ initPainter(p);
+ p.drawEllipse( (int)x()-16, (int)y()-16, width(), width() );
+ p.setPen(QPen(Qt::black,2));
+ p.setBrush(Qt::black);
+
+ // The proportion between 0.1mV and 10KV, on a logarithmic scale
+ double prop;
+ const double abs_value = std::abs(m_old_value);
+ if ( abs_value <= m_minValue )
+ prop = 0.;
+ else if ( abs_value >= m_maxValue )
+ prop = 1.;
+ else
+ prop = std::log10( abs_value/m_minValue ) / std::log10( m_maxValue/m_minValue );
+ if ( m_old_value>0 )
+ prop *= -1;
+ double sin_prop = 10*std::sin(prop*1.571); // 1.571 = pi/2
+ double cos_prop = 10*std::cos(prop*1.571); // 1.571 = pi/2
+
+ int cx = int(x()-16+(width()/2));
+ int cy = int(y()-16+(height()/2));
+ p.drawLine( int(cx-sin_prop), int(cy-cos_prop), int(cx+sin_prop), int(cy+cos_prop) );
+
+ QPointArray pa(3);
+ pa[0] = QPoint( int(cx-sin_prop), int(cy-cos_prop) ); // Arrow head
+ pa[1] = QPoint( int(cx-sin_prop + 8*std::sin(1.571*(-0.3+prop))), int(cy-cos_prop + 8*std::cos(1.571*(-0.3+prop))) );
+ pa[2] = QPoint( int(cx-sin_prop + 8*std::sin(1.571*(0.3+prop))), int(cy-cos_prop + 8*std::cos(1.571*(0.3+prop))) );
+ p.drawPolygon(pa);
+
+ deinitPainter(p);
+}
+
+
+QString Meter::displayText()
+{
+ double value = m_avgValue/m_timeSinceUpdate;
+ if ( !std::isfinite(value) ) value = m_old_value;
+ if ( std::abs((value)) < 1e-9 ) value = 0.;
+ m_old_value = value;
+ m_avgValue = 0.;
+ m_timeSinceUpdate = 0.;
+ b_timerStarted = false;
+ return QString::number( value/CNItem::getMultiplier(value), 'g', 3 ) + CNItem::getNumberMag(value) + m_unit;
+}
+//END class Meter
+
+
+//BEGIN class FrequencyMeter
+Item* FrequencyMeter::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new FrequencyMeter( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* FrequencyMeter::libraryItem()
+{
+ return new LibraryItem(
+ QString("ec/frequencymeter"),
+ i18n("Frequency Meter (TODO)"),
+ i18n("Outputs"),
+ "frequencymeter.png",
+ LibraryItem::lit_component,
+ FrequencyMeter::construct );
+}
+
+FrequencyMeter::FrequencyMeter( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Meter( icnDocument, newItem, (id) ? id : "frequencymeter" )
+{
+ m_name = i18n("Frequency Meter");
+ m_desc = i18n("Place this at the point where frequency is to be measured.");
+ m_unit = "Hz";
+
+ m_probeNode = createPin( 0, -24, 90, "n1" );
+}
+
+FrequencyMeter::~FrequencyMeter()
+{
+}
+
+double FrequencyMeter::meterValue()
+{
+ return 0;
+}
+//END class FrequencyMeter
+
+
+//BEGIN class ECAmmeter
+Item* ECAmmeter::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECAmmeter( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ECAmmeter::libraryItem()
+{
+ QStringList ids;
+ ids << "ec/ammeter" << "ec/ammmeter";
+ return new LibraryItem(
+ ids,
+ i18n("Ammeter"),
+ i18n("Outputs"),
+ "ammeter.png",
+ LibraryItem::lit_component,
+ ECAmmeter::construct
+ );
+}
+
+ECAmmeter::ECAmmeter( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Meter( icnDocument, newItem, (id) ? id : "ammeter" )
+{
+ m_name = i18n("Ammeter");
+ m_desc = i18n("Place this in series in the circuit to measure the current flowing.");
+ setSize( -16, -16, 32, 32 );
+ m_unit = "A";
+
+ init1PinLeft(0);
+ init1PinRight(0);
+
+ m_voltageSource = createVoltageSource( m_pNNode[0], m_pPNode[0], 0. );
+}
+
+ECAmmeter::~ECAmmeter()
+{
+}
+
+double ECAmmeter::meterValue()
+{
+ return -m_voltageSource->cbranchCurrent(0);
+}
+//END class ECAmmeter
+
+
+//BEGIN class ECVoltmeter
+Item* ECVoltMeter::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECVoltMeter( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ECVoltMeter::libraryItem()
+{
+ return new LibraryItem(
+ QString("ec/voltmeter"),
+ i18n("Voltmeter"),
+ i18n("Outputs"),
+ "voltmeter.png",
+ LibraryItem::lit_component,
+ ECVoltMeter::construct );
+}
+
+ECVoltMeter::ECVoltMeter( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Meter( icnDocument, newItem, (id) ? id : "voltmeter" )
+{
+ m_name = i18n("Voltmeter");
+ m_desc = i18n("Place this in parallel in the circuit to meaure the voltage between two points.");
+ m_unit = "V";
+
+ init1PinLeft(0);
+ init1PinRight(0);
+}
+
+ECVoltMeter::~ECVoltMeter()
+{
+}
+
+double ECVoltMeter::meterValue()
+{
+ return m_pNNode[0]->pin()->voltage() - m_pPNode[0]->pin()->voltage();
+}
+//END class ECVoltMeter
+
diff --git a/src/electronics/components/meter.h b/src/electronics/components/meter.h
new file mode 100644
index 0000000..fa52e95
--- /dev/null
+++ b/src/electronics/components/meter.h
@@ -0,0 +1,103 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef METER_H
+#define METER_H
+
+#include <component.h>
+
+/**
+@author David Saxton
+*/
+class Meter : public Component
+{
+public:
+ Meter( ICNDocument *icnDocument, bool newItem, const char *id );
+ ~Meter();
+
+ virtual void stepNonLogic();
+ virtual bool doesStepNonLogic() const { return true; }
+ virtual void drawShape( QPainter &p );
+
+protected:
+ QString displayText();
+ virtual void dataChanged();
+ /**
+ * Return the value / current, or whatever the meter is measuring
+ */
+ virtual double meterValue() = 0;
+
+ bool b_firstRun; // If true, then update the text dispalyed
+ bool b_timerStarted; // The timer to change the text is started on change
+ double m_timeSinceUpdate;
+ double m_avgValue;
+ double m_old_value;
+ double m_minValue;
+ double m_maxValue;
+ Text *p_displayText;
+ QString m_unit;
+};
+
+/**
+@short Measures the frequency at a point in the circuit
+@author David Saxton
+*/
+class FrequencyMeter : public Meter
+{
+public:
+ FrequencyMeter( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~FrequencyMeter();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+protected:
+ virtual double meterValue();
+ ECNode *m_probeNode;
+};
+
+/**
+@short Simple resistor
+@author David Saxton
+*/
+class ECAmmeter : public Meter
+{
+public:
+ ECAmmeter( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECAmmeter();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+protected:
+ virtual double meterValue();
+
+private:
+ VoltageSource *m_voltageSource;
+};
+
+/**
+@short Displays voltage across terminals
+@author David Saxton
+*/
+class ECVoltMeter : public Meter
+{
+public:
+ ECVoltMeter( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECVoltMeter();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+protected:
+ virtual double meterValue();
+};
+
+#endif
diff --git a/src/electronics/components/multiinputgate.cpp b/src/electronics/components/multiinputgate.cpp
new file mode 100644
index 0000000..7453845
--- /dev/null
+++ b/src/electronics/components/multiinputgate.cpp
@@ -0,0 +1,530 @@
+/***************************************************************************
+ * Copyright (C) 2004-2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "ecnode.h"
+#include "icndocument.h"
+#include "libraryitem.h"
+#include "multiinputgate.h"
+#include "logic.h"
+
+#include <cmath>
+#include <klocale.h>
+#include <qpainter.h>
+
+//BEGIN class MultiInputGate
+MultiInputGate::MultiInputGate( ICNDocument *icnDocument, bool newItem, const char *id, int baseWidth )
+ : Component( icnDocument, newItem, id )
+{
+ b_doneInit = false;
+ m_numInputs = 0;
+ if ( baseWidth == -1 ) {
+ baseWidth = 32;
+ }
+ m_baseWidth = baseWidth;
+
+ for ( int i=0; i<maxGateInput; ++i )
+ {
+ inLogic[i] = 0l;
+ inNode[i] = 0l;
+ }
+
+ updateInputs(2);
+
+ init1PinRight(16);
+ m_pOut = createLogicOut( m_pPNode[0], false );
+
+
+ createProperty( "numInput", Variant::Type::Int );
+ property("numInput")->setCaption( i18n("Number Inputs") );
+ property("numInput")->setMinValue(2);
+ property("numInput")->setMaxValue(maxGateInput);
+ property("numInput")->setValue(2);
+
+ b_doneInit = true;
+}
+
+
+MultiInputGate::~MultiInputGate()
+{
+}
+
+
+void MultiInputGate::dataChanged()
+{
+ updateInputs( QMIN( maxGateInput, dataInt("numInput") ) );
+}
+
+
+void MultiInputGate::updateInputs( int newNum )
+{
+ if ( newNum == m_numInputs ) {
+ return;
+ }
+
+ if ( newNum < 2 ) {
+ newNum = 2;
+ }
+ else if ( newNum > maxGateInput ) {
+ newNum = maxGateInput;
+ }
+
+ const int newWidth = m_baseWidth;
+
+ setSize( -newWidth/2, -8*newNum, newWidth, 16*newNum, true );
+
+ const bool added = ( newNum > m_numInputs );
+ if (added)
+ {
+ for ( int i = m_numInputs; i<newNum; ++i )
+ {
+ ECNode *node = createPin( 0, 0, 0, "in"+QString::number(i) );
+ inNode[i] = node;
+ inLogic[i] = createLogicIn(node);
+ inLogic[i]->setCallback( this, (CallbackPtr)(&MultiInputGate::inStateChanged) );
+ }
+ }
+ else
+ {
+ for ( int i=newNum; i<m_numInputs; ++i )
+ {
+ removeNode("in"+QString::number(i));
+ removeElement( inLogic[i], false );
+ inNode[i] = 0l;
+ inLogic[i] = 0l;
+ }
+ }
+
+ m_numInputs = newNum;
+
+ // We can't call a pure-virtual function if we haven't finished our constructor yet...
+ if (b_doneInit)
+ inStateChanged(!added);
+
+ updateAttachedPositioning();
+}
+
+
+void MultiInputGate::updateAttachedPositioning()
+{
+ // Check that our ndoes have been created before we attempt to use them
+ if ( !m_nodeMap.contains("p1") || !m_nodeMap.contains("in"+QString::number(m_numInputs-1)) )
+ return;
+
+ int _x = offsetX()+8;
+ int _y = offsetY()+8;
+
+ m_nodeMap["p1"].x = m_baseWidth/2 + 8;
+ m_nodeMap["p1"].y = 0;
+
+ for ( int i=0; i< m_numInputs; ++i )
+ {
+ m_nodeMap["in"+QString::number(i)].x = _x - 16;
+ m_nodeMap["in"+QString::number(i)].y = _y + 16*i;
+ }
+
+ if (b_doneInit)
+ Component::updateAttachedPositioning();
+}
+//END class MultiInputGate
+
+
+//BEGIN class ECXNor
+Item* ECXnor::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECXnor( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ECXnor::libraryItem()
+{
+ return new LibraryItem(
+ QString::QString("ec/xnor"),
+ i18n("XNOR gate"),
+ i18n("Logic"),
+ "xnor.png",
+ LibraryItem::lit_component,
+ ECXnor::construct );
+}
+
+ECXnor::ECXnor( ICNDocument *icnDocument, bool newItem, const char *id )
+ : MultiInputGate( icnDocument, newItem, (id) ? id : "xnor", 48 )
+{
+ m_name = i18n("XNOR gate");
+ m_desc = i18n("Exclusive NOR gate. Output is low when exactly one input is high.");
+
+ inStateChanged(false);
+}
+
+ECXnor::~ECXnor()
+{
+}
+
+void ECXnor::inStateChanged(bool)
+{
+ int highCount = 0;
+ for ( int i=0; i<m_numInputs; ++i )
+ {
+ if ( inLogic[i]->isHigh() )
+ highCount++;
+ }
+
+ m_pOut->setHigh( highCount != 1 );
+}
+
+void ECXnor::drawShape( QPainter &p )
+{
+ initPainter(p);
+ int _x = (int)x()+offsetX();
+ int _y = (int)y()+offsetY();
+
+ p.save();
+ p.setPen( Qt::NoPen );
+ p.drawChord( _x-width()+22, _y, 2*width()-28, height(), -16*81, 16*162 );
+ p.restore();
+
+ p.drawArc( _x-width()+22, _y, 2*width()-28, height(), -16*90, 16*180 );
+ p.drawArc( _x-8, _y, 16, height(), -16*90, 16*180 );
+ p.drawArc( _x, _y, 16, height(), -16*90, 16*180 );
+
+ p.drawEllipse( _x+width()-6, _y+(height()/2)-3, 6, 6 );
+
+ const int n = m_numInputs;
+ for ( int i=0; i<n; ++i )
+ {
+ p.setPen( inNode[i]->isSelected() ? m_selectedCol : Qt::black );
+ int pin_x = (int)std::sqrt((double)(64*n*n - (8*n-8-16*i)*(8*n-8-16*i)))/n;
+ p.drawLine( _x, _y+16*i+8, _x+pin_x, _y+16*i+8 );
+ }
+
+ deinitPainter(p);
+}
+//END class ECXnor
+
+
+//BEGIN class ECXor
+Item* ECXor::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECXor( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ECXor::libraryItem()
+{
+ return new LibraryItem(
+ QString::QString("ec/xor"),
+ i18n("XOR gate"),
+ i18n("Logic"),
+ "xor.png",
+ LibraryItem::lit_component,
+ ECXor::construct );
+}
+
+ECXor::ECXor( ICNDocument *icnDocument, bool newItem, const char *id )
+ : MultiInputGate( icnDocument, newItem, (id) ? id : "xor", 48 )
+{
+ m_name = i18n("XOR gate");
+ m_desc = i18n("Exclusive OR gate. Output is high when exactly one input is high.");
+
+ inStateChanged(false);
+}
+
+ECXor::~ECXor()
+{
+}
+
+void ECXor::inStateChanged(bool)
+{
+ int highCount = 0;
+ for ( int i=0; i<m_numInputs; ++i )
+ {
+ if ( inLogic[i]->isHigh() )
+ highCount++;
+ }
+
+ m_pOut->setHigh( highCount == 1 );
+}
+
+void ECXor::drawShape( QPainter &p )
+{
+ initPainter(p);
+ int _x = (int)x()+offsetX();
+ int _y = (int)y()+offsetY();
+
+ p.save();
+ p.setPen( Qt::NoPen );
+ p.drawChord( _x-width()+16, _y, 2*width()-16, height(), -16*81, 16*162 );
+ p.restore();
+
+ p.drawArc( _x-width()+16, _y, 2*width()-16, height(), -16*90, 16*180 );
+ p.drawArc( _x-8, _y, 16, height(), -16*90, 16*180 );
+ p.drawArc( _x, _y, 16, height(), -16*90, 16*180 );
+
+ const int n = m_numInputs;
+ for ( int i=0; i<n; ++i )
+ {
+ p.setPen( inNode[i]->isSelected() ? m_selectedCol : Qt::black );
+ int pin_x = (int)std::sqrt((double)(64*n*n - (8*n-8-16*i)*(8*n-8-16*i)))/n;
+ p.drawLine( _x, _y+16*i+8, _x+pin_x, _y+16*i+8 );
+ }
+
+ deinitPainter(p);
+}
+//END class ECXor
+
+
+//BEGIN class EXOr
+Item* ECOr::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECOr( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ECOr::libraryItem()
+{
+ return new LibraryItem(
+ QString::QString("ec/or"),
+ i18n("OR gate"),
+ i18n("Logic"),
+ "or.png",
+ LibraryItem::lit_component,
+ ECOr::construct );
+}
+
+ECOr::ECOr( ICNDocument *icnDocument, bool newItem, const char *id )
+ : MultiInputGate( icnDocument, newItem, (id) ? id : "or", 48 )
+{
+ m_name = i18n("OR gate");
+ m_desc = i18n("The output is high when at least one of the inputs is high; or low when all of the inputs are off");
+
+ inStateChanged(false);
+}
+
+ECOr::~ECOr()
+{
+}
+
+void ECOr::inStateChanged(bool)
+{
+ bool allLow = true;
+ for ( int i=0; i<m_numInputs && allLow; ++i )
+ {
+ if ( inLogic[i]->isHigh() )
+ allLow = false;
+ }
+
+ m_pOut->setHigh(!allLow);
+}
+
+void ECOr::drawShape( QPainter &p )
+{
+ initPainter(p);
+ int _x = (int)x()+offsetX();
+ int _y = (int)y()+offsetY();
+
+ p.save();
+ p.setPen( Qt::NoPen );
+// p.setBrush( Qt::red );
+ p.drawChord( _x-width(), _y, 2*width(), height(), -16*81, 16*162 );
+// p.drawPie( _x-width()+16, _y, 2*width()-16, height(), -16*100, 16*200 );
+ p.restore();
+
+ p.drawArc( _x-width(), _y, 2*width(), height(), -16*90, 16*180 );
+ p.drawArc( _x-8, _y, 16, height(), -16*90, 16*180 );
+
+ const int n = m_numInputs;
+ for ( int i=0; i<n; ++i )
+ {
+ p.setPen( inNode[i]->isSelected() ? m_selectedCol : Qt::black );
+ int pin_x = (int)std::sqrt((double)(64*n*n - (8*n-8-16*i)*(8*n-8-16*i)))/n;
+ p.drawLine( _x, _y+16*i+8, _x+pin_x, _y+16*i+8 );
+ }
+
+ deinitPainter(p);
+}
+//END class ECOr
+
+
+//BEGIN class ECNor
+Item* ECNor::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECNor( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ECNor::libraryItem()
+{
+ return new LibraryItem(
+ QString::QString("ec/nor"),
+ i18n("NOR gate"),
+ i18n("Logic"),
+ "nor.png",
+ LibraryItem::lit_component,
+ ECNor::construct );
+}
+
+ECNor::ECNor( ICNDocument *icnDocument, bool newItem, const char *id )
+ : MultiInputGate( icnDocument, newItem, (id) ? id : "nor", 48 )
+{
+ m_name = i18n("NOR Gate");
+ m_desc = i18n("The output is high when all inputs are low.");
+
+ inStateChanged(false);
+}
+
+ECNor::~ECNor()
+{
+}
+
+void ECNor::inStateChanged(bool)
+{
+ bool allLow = true;
+ for ( int i=0; i<m_numInputs && allLow; ++i )
+ {
+ if ( inLogic[i]->isHigh() )
+ allLow = false;
+ }
+
+ m_pOut->setHigh(allLow);
+}
+
+void ECNor::drawShape( QPainter &p )
+{
+ initPainter(p);
+ int _x = (int)x()+offsetX();
+ int _y = (int)y()+offsetY();
+
+ p.save();
+ p.setPen( Qt::NoPen );
+ p.drawChord( _x-width()+6, _y, 2*width()-12, height(), -16*81, 16*162 );
+ p.restore();
+
+ p.drawArc( _x-width()+6, _y, 2*width()-12, height(), -16*90, 16*180 );
+ p.drawArc( _x-8, _y, 16, height(), -16*90, 16*180 );
+
+ p.drawEllipse( _x+width()-6, _y+(height()/2)-3, 6, 6 );
+
+ const int n = m_numInputs;
+ for ( int i=0; i<n; ++i )
+ {
+ p.setPen( inNode[i]->isSelected() ? m_selectedCol : Qt::black );
+ int pin_x = (int)std::sqrt((double)(64*n*n - (8*n-8-16*i)*(8*n-8-16*i)))/n;
+ p.drawLine( _x, _y+16*i+8, _x+pin_x, _y+16*i+8 );
+ }
+
+ deinitPainter(p);
+}
+//END class ECNor
+
+
+//BEGIN class ECNand
+Item* ECNand::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECNand( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ECNand::libraryItem()
+{
+ return new LibraryItem(
+ QString::QString("ec/nand"),
+ i18n("NAND gate"),
+ i18n("Logic"),
+ "nand.png",
+ LibraryItem::lit_component,
+ ECNand::construct );
+}
+
+ECNand::ECNand( ICNDocument *icnDocument, bool newItem, const char *id )
+ : MultiInputGate( icnDocument, newItem, id ? id : "nand" )
+{
+ m_name = i18n("NAND Gate");
+ m_desc = i18n("The output is low only when all of the inputs are high.");
+
+ inStateChanged(false);
+}
+
+ECNand::~ECNand()
+{
+}
+
+void ECNand::inStateChanged(bool)
+{
+ bool allHigh = true;
+ for ( int i=0; i<m_numInputs && allHigh; ++i )
+ {
+ if ( !inLogic[i]->isHigh() )
+ allHigh = false;
+ }
+
+ m_pOut->setHigh(!allHigh);
+}
+
+void ECNand::drawShape( QPainter &p )
+{
+ initPainter(p);
+ int _x = (int)x()+offsetX();
+ int _y = (int)y()+offsetY();
+ p.drawChord( _x-width()+6, _y, 2*width()-12, height(), -16*90, 16*180 );
+ p.drawEllipse( _x+width()-6, _y+(height()/2)-3, 6, 6 );
+ deinitPainter(p);
+}
+//END class ECNand
+
+
+//BEGIN class ECAnd
+Item* ECAnd::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECAnd( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ECAnd::libraryItem()
+{
+ QStringList idList;
+ idList << "ec/and" << "ec/and_2";
+ return new LibraryItem(
+ idList,
+ i18n("AND gate"),
+ i18n("Logic"),
+ "and.png",
+ LibraryItem::lit_component,
+ ECAnd::construct );
+}
+
+ECAnd::ECAnd( ICNDocument *icnDocument, bool newItem, const char *id )
+ : MultiInputGate( icnDocument, newItem, id ? id : "and" )
+{
+ m_name = i18n("AND Gate");
+ m_desc = i18n("The output is high if and only if all of the inputs are high.");
+
+ inStateChanged(false);
+}
+
+ECAnd::~ECAnd()
+{
+}
+
+void ECAnd::inStateChanged(bool)
+{
+ bool allHigh = true;
+ for ( int i=0; i<m_numInputs && allHigh; ++i )
+ {
+ if ( !inLogic[i]->isHigh() )
+ allHigh = false;
+ }
+
+ m_pOut->setHigh(allHigh);
+}
+
+void ECAnd::drawShape( QPainter &p )
+{
+ initPainter(p);
+
+ int _x = (int)x()+offsetX();
+ int _y = (int)y()+offsetY();
+ p.drawChord( _x-width(), _y, 2*width(), height(), -16*90, 16*180 );
+
+ deinitPainter(p);
+}
+//END class ECAnd
diff --git a/src/electronics/components/multiinputgate.h b/src/electronics/components/multiinputgate.h
new file mode 100644
index 0000000..1981217
--- /dev/null
+++ b/src/electronics/components/multiinputgate.h
@@ -0,0 +1,160 @@
+/***************************************************************************
+ * Copyright (C) 2004-2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef MULTIINPUTGATE_H
+#define MULTIINPUTGATE_H
+
+#include "component.h"
+#include "logic.h"
+
+const int maxGateInput = 256;
+
+/**
+@author David Saxton
+*/
+class MultiInputGate : public CallbackClass, public Component
+{
+public:
+ MultiInputGate( ICNDocument *icnDocument, bool newItem, const char *id, int baseWidth = -1 );
+ ~MultiInputGate();
+
+protected:
+ virtual void inStateChanged( bool newState ) = 0;
+ void dataChanged();
+ void updateInputs( int newNum );
+
+ int m_numInputs;
+ int m_baseWidth;
+
+ LogicIn *inLogic[maxGateInput];
+ ECNode *inNode[maxGateInput];
+
+ LogicOut * m_pOut;
+
+ virtual void updateAttachedPositioning();
+
+private:
+ bool b_doneInit;
+};
+
+
+/**
+@short Boolean XNOR
+@author David Saxton
+*/
+class ECXnor : public MultiInputGate
+{
+public:
+ ECXnor( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECXnor();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+private:
+ void inStateChanged( bool newState );
+ virtual void drawShape( QPainter &p );
+};
+
+
+/**
+@short Boolean XOR
+@author David Saxton
+*/
+class ECXor : public MultiInputGate
+{
+public:
+ ECXor( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECXor();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+protected:
+ void inStateChanged( bool newState );
+ virtual void drawShape( QPainter &p );
+};
+
+
+/**
+@short Boolean OR
+@author David Saxton
+*/
+class ECOr : public MultiInputGate
+{
+public:
+ ECOr( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECOr();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+protected:
+ void inStateChanged( bool newState );
+ virtual void drawShape( QPainter &p );
+};
+
+/**
+@short Boolean NOR
+@author David Saxton
+*/
+class ECNor : public MultiInputGate
+{
+public:
+ ECNor( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECNor();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+private:
+ void inStateChanged( bool newState );
+ virtual void drawShape( QPainter &p );
+};
+
+/**
+@short Boolean NAND
+@author David Saxton
+*/
+class ECNand : public MultiInputGate
+{
+public:
+ ECNand( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECNand();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+private:
+ void inStateChanged( bool newState );
+ virtual void drawShape( QPainter &p );
+};
+
+/**
+@short Boolean AND
+@author David Saxton
+*/
+class ECAnd : public MultiInputGate
+{
+public:
+ ECAnd( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECAnd();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+private:
+ void inStateChanged( bool newState );
+ virtual void drawShape( QPainter &p );
+};
+
+
+
+#endif
diff --git a/src/electronics/components/multiplexer.cpp b/src/electronics/components/multiplexer.cpp
new file mode 100644
index 0000000..e421fee
--- /dev/null
+++ b/src/electronics/components/multiplexer.cpp
@@ -0,0 +1,176 @@
+/***************************************************************************
+ * Copyright (C) 2004-2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "multiplexer.h"
+
+#include "logic.h"
+#include "libraryitem.h"
+
+#include <kiconloader.h>
+#include <klocale.h>
+
+#include <cmath>
+
+Item* Multiplexer::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new Multiplexer( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* Multiplexer::libraryItem()
+{
+ return new LibraryItem(
+ QString("ec/multiplexer"),
+ i18n("Multiplexer"),
+ i18n("Integrated Circuits"),
+ "ic1.png",
+ LibraryItem::lit_component,
+ Multiplexer::construct
+ );
+}
+
+Multiplexer::Multiplexer( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, (id) ? id : "multiplexer" )
+{
+ m_name = i18n("Multiplexer");
+ m_desc = i18n("Combines the input data stream into one single stream. The value of the input selected by the \"A\" inputs is passed to the output.");
+
+ m_output = 0l;
+
+ createProperty( "addressSize", Variant::Type::Int );
+ property("addressSize")->setCaption( i18n("Address Size") );
+ property("addressSize")->setMinValue(1);
+ property("addressSize")->setMaxValue(8);
+ property("addressSize")->setValue(1);
+
+ // For backwards compatibility
+ createProperty( "numInput", Variant::Type::Int );
+ property("numInput")->setMinValue(-1);
+ property("numInput")->setValue(-1);
+ property("numInput")->setHidden(true);
+}
+
+Multiplexer::~Multiplexer()
+{
+}
+
+
+void Multiplexer::dataChanged()
+{
+ if ( hasProperty("numInput") && dataInt("numInput") != -1 )
+ {
+ int addressSize = int( std::ceil( std::log( (double)dataInt("numInput") ) / std::log(2.0) ) );
+ property("numInput")->setValue(-1);
+
+ if ( addressSize < 1 )
+ addressSize = 1;
+ else if ( addressSize > 8 )
+ addressSize = 8;
+
+ // This function will get called again when we set the value of numInput
+ property("addressSize")->setValue(addressSize);
+ return;
+ }
+
+ if ( hasProperty("numInput") )
+ {
+ m_variantData["numInput"]->deleteLater();
+ m_variantData.remove("numInput");
+ }
+
+ initPins( unsigned(dataInt("addressSize")) );
+}
+
+
+void Multiplexer::inStateChanged( bool /*state*/ )
+{
+ unsigned long long pos = 0;
+ for ( unsigned i = 0; i < m_aLogic.size(); ++i )
+ {
+ if ( m_aLogic[i]->isHigh() )
+ pos += 1 << i;
+ }
+ m_output->setHigh( m_xLogic[pos]->isHigh() );
+}
+
+
+void Multiplexer::initPins( unsigned newAddressSize )
+{
+ unsigned oldAddressSize = m_aLogic.size();
+ unsigned long long oldXLogicCount = m_xLogic.size();
+ unsigned long long newXLogicCount = 1 << newAddressSize;
+
+ if ( newXLogicCount == oldXLogicCount )
+ return;
+
+ QStringList pins;
+
+ const int length = newAddressSize + newXLogicCount;
+
+ for ( unsigned i=0; i<newAddressSize; ++i )
+ pins += "A"+QString::number(i);
+ for ( unsigned i=0; i<newXLogicCount; ++i )
+ pins += "X"+QString::number(i);
+ for ( int i=0; i<(length-(length%2))/2; ++i )
+ pins += "";
+ pins += "X";
+ for ( int i=0; i<((length+(length%2))/2)-1; ++i )
+ pins += "";
+
+ initDIPSymbol( pins, 64 );
+ initDIP(pins);
+
+ ECNode *node;
+
+ if (!m_output)
+ {
+ node = ecNodeWithID("X");
+ m_output = createLogicOut( node, false );
+ }
+
+ if ( newXLogicCount > oldXLogicCount )
+ {
+ m_xLogic.resize(newXLogicCount);
+ for ( unsigned i=oldXLogicCount; i<newXLogicCount; ++i )
+ {
+ node = ecNodeWithID("X"+QString::number(i));
+ m_xLogic.insert( i, createLogicIn(node) );
+ m_xLogic[i]->setCallback( this, (CallbackPtr)(&Multiplexer::inStateChanged) );
+ }
+
+ m_aLogic.resize(newAddressSize);
+ for ( unsigned i=oldAddressSize; i<newAddressSize; ++i )
+ {
+ node = ecNodeWithID("A"+QString::number(i));
+ m_aLogic.insert( i, createLogicIn(node) );
+ m_aLogic[i]->setCallback( this, (CallbackPtr)(&Multiplexer::inStateChanged) );
+ }
+ }
+ else
+ {
+ for ( unsigned i = newXLogicCount; i < oldXLogicCount; ++i )
+ {
+ QString id = "X"+QString::number(i);
+ removeDisplayText(id);
+ removeElement( m_xLogic[i], false );
+ removeNode(id);
+ }
+ m_xLogic.resize(newXLogicCount);
+
+ for ( unsigned i = newAddressSize; i < oldAddressSize; ++i )
+ {
+ QString id = "A"+QString::number(i);
+ removeDisplayText(id);
+ removeElement( m_aLogic[i], false );
+ removeNode(id);
+ }
+ m_aLogic.resize(newAddressSize);
+ }
+}
+
diff --git a/src/electronics/components/multiplexer.h b/src/electronics/components/multiplexer.h
new file mode 100644
index 0000000..42bcfc1
--- /dev/null
+++ b/src/electronics/components/multiplexer.h
@@ -0,0 +1,46 @@
+/***************************************************************************
+ * Copyright (C) 2004-2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef MULTIPLEXER_H
+#define MULTIPLEXER_H
+
+#include "component.h"
+#include "logic.h"
+
+#include <qptrvector.h>
+
+/**
+@author David Saxton
+*/
+class Multiplexer : public CallbackClass, public Component
+{
+public:
+ Multiplexer( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~Multiplexer();
+
+ virtual bool canFlip() const { return true; }
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+protected:
+ void dataChanged();
+ /**
+ * Add / remove pins according to the number of inputs the user has requested
+ */
+ void initPins( unsigned addressSize );
+
+ void inStateChanged( bool newState );
+
+ QPtrVector<LogicIn> m_aLogic;
+ QPtrVector<LogicIn> m_xLogic;
+ LogicOut * m_output;
+};
+
+#endif
diff --git a/src/electronics/components/parallelportcomponent.cpp b/src/electronics/components/parallelportcomponent.cpp
new file mode 100644
index 0000000..9bc17b4
--- /dev/null
+++ b/src/electronics/components/parallelportcomponent.cpp
@@ -0,0 +1,241 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "port.h"
+#include "parallelportcomponent.h"
+
+#include "ecnode.h"
+#include "itemdocument.h"
+#include "libraryitem.h"
+#include "pin.h"
+#include "resistance.h"
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <qpainter.h>
+
+#include <cmath>
+#include <termios.h>
+
+Item* ParallelPortComponent::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ParallelPortComponent( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ParallelPortComponent::libraryItem()
+{
+ return new LibraryItem(
+ "ec/parallel_port",
+ i18n("Parallel Port"),
+ i18n("Connections"),
+ "ic1.png",
+ LibraryItem::lit_component,
+ ParallelPortComponent::construct
+ );
+}
+
+ParallelPortComponent::ParallelPortComponent( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, id ? id : "parallel_port" )
+{
+ m_name = i18n("Parallel Port");
+ m_desc = i18n("The pins are divided into 3 registers.<br><br>"
+ "<b>Data Pins</b><br><br>"
+ "The data pins can be configured as either all input or all output. They are:"
+ "<ul>"
+ "<li><b>D<i>[0..7]</i></b></li>"
+ "</ul><br>"
+ "<b>Status Pins</b><br><br>"
+ "The status pins are read-only. They area:"
+ "<ul>"
+ "<li><b>ERR</b> - Error</li>"
+ "<li><b>ON</b> - Online</li>"
+ "<li><b>PE</b> - Paper End</li>"
+ "<li><b>ACK</b> - Acknowledge</li>"
+ "<li><b>BUSY</b> - Busy</li>"
+ "</ul><br>"
+ "<b>Control Pins</b>"
+ "<ul>"
+ "<li><b>STR</b> - Strobe</li>"
+ "<li><b>AUT</b> - Auto Feed</li>"
+ "<li><b>INIT</b> - Init</li>"
+ "<li><b>SEL</b> - Select</li>"
+ "</ul><br>"
+ "The remaining pins are all ground."
+ );
+
+ QPointArray pa( 4 );
+ pa[0] = QPoint( -32, -112 );
+ pa[1] = QPoint( 32, -104 );
+ pa[2] = QPoint( 32, 104 );
+ pa[3] = QPoint( -32, 112 );
+ setItemPoints( pa );
+
+ m_pParallelPort = new ParallelPort();
+
+ for ( unsigned i = 0; i < 24; ++i )
+ m_pLogic[i] = 0;
+
+ ECNode * pin = 0;
+
+ //BEGIN Data register
+ for ( int i = 0; i < 8; ++i )
+ {
+ QString id = QString("D%1").arg(i);
+ QString name = id;
+
+ pin = createPin( -40, -80 + 16*i, 0, id );
+ addDisplayText( id, QRect( -28, -88 + 16*i, 28, 16 ), name, true, Qt::AlignLeft | Qt::AlignVCenter );
+
+ m_pLogic[i] = createLogicOut( pin, false );
+ m_pLogic[i]->setCallback( this, (CallbackPtr)(&ParallelPortComponent::dataCallback) );
+ }
+ //END Data register
+
+
+ //BEGIN Status register
+ QString statusNames[] = { "ERR", "ON", "PE", "ACK", "BUSY" };
+
+ // The statusIDs are referenced in the save file and must not change
+ QString statusIDs[] = { "ERROR", "ONLINE", "PE", "ACK", "BUSY" };
+
+ // Bits 0...2 in the Status register are not used
+ for ( int i = 3; i < 8; ++i )
+ {
+ QString id = statusIDs[i-3];
+ QString name = statusNames[i-3];
+
+ // Bit 3 (pin 15) doesn't not follow the same positioning pattern as
+ // the other pins in the Status register.
+ if ( i == 3 )
+ {
+ pin = createPin( 40, -72, 180, id );
+ addDisplayText( id, QRect( 0, -80, 28, 16 ), name, true, Qt::AlignRight | Qt::AlignVCenter );
+ }
+ else
+ {
+ pin = createPin( -40, -16 + 16*i, 0, id );
+ addDisplayText( id, QRect( -28, -24 + 16*i, 28, 16 ), name, true, Qt::AlignLeft | Qt::AlignVCenter );
+ }
+
+ m_pLogic[i+8] = createLogicOut( pin, false );
+ }
+ //END Status register
+
+
+ //BEGIN Control register
+ QString controlNames[] = { "STR", "AUT", "INIT", "SEL" };
+
+ // The controlIDs are referenced in the save file and must not change
+ QString controlIDs[] = { "STROBE", "AUTO", "INIT", "SELECT" };
+
+ // Bits 4..7 are not used (well; bit 5 is, but not as a pin)
+ for ( int i = 0; i < 4; ++i )
+ {
+ QString id = controlIDs[i];
+ QString name = controlNames[i];
+
+ if ( i == 0 )
+ {
+ pin = createPin( -40, -96, 0, id );
+ addDisplayText( id, QRect( -28, -104, 28, 16 ), name, true, Qt::AlignLeft | Qt::AlignVCenter );
+ }
+ else if ( i == 1 )
+ {
+ pin = createPin( 40, -88, 180, id );
+ addDisplayText( id, QRect( 0, -96, 28, 16 ), name, true, Qt::AlignRight | Qt::AlignVCenter );
+ }
+ else
+ {
+ pin = createPin( 40, -88 + i*16, 180, id );
+ addDisplayText( id, QRect( 0, -96 + i*16, 28, 16 ), name, true, Qt::AlignRight | Qt::AlignVCenter );
+ }
+
+ m_pLogic[i+16] = createLogicOut( pin, false );
+ m_pLogic[i+16]->setCallback( this, (CallbackPtr)(&ParallelPortComponent::controlCallback) );
+ }
+ //END Control register
+
+
+#if 0
+ // And make the rest of the pins ground
+ for ( int i = 0; i < 8; ++i )
+ {
+ pin = createPin( 40, -24 + i*16, 180, QString("GND%1").arg( i ) );
+ pin->pin()->setGroundType( Pin::gt_always );
+ }
+#endif
+
+ Variant * v = createProperty( "port", Variant::Type::Combo );
+ v->setAllowed( ParallelPort::ports( Port::ExistsAndRW ) );
+ v->setCaption( i18n("Port") );
+}
+
+
+ParallelPortComponent::~ParallelPortComponent()
+{
+ delete m_pParallelPort;
+}
+
+
+void ParallelPortComponent::dataChanged()
+{
+ initPort( dataString("port") );
+}
+
+
+void ParallelPortComponent::initPort( const QString & port )
+{
+ if ( port.isEmpty() )
+ {
+ m_pParallelPort->closePort();
+ return;
+ }
+
+ if ( ! m_pParallelPort->openPort( port ) )
+ {
+ p_itemDocument->canvas()->setMessage( i18n("Could not open port %1").arg( port ) );
+ return;
+ }
+}
+
+
+void ParallelPortComponent::dataCallback( bool )
+{
+ uchar value = 0;
+ for ( unsigned i = 0; i < 8; ++ i )
+ value |= m_pLogic[ i + 0 ]->isHigh() ? 0 : (1 << i);
+
+ m_pParallelPort->writeToData( value );
+}
+
+
+void ParallelPortComponent::controlCallback( bool )
+{
+ uchar value = 0;
+ for ( unsigned i = 0; i < 4; ++ i )
+ value |= m_pLogic[ i + 16 ]->isHigh() ? 0 : (1 << i);
+
+ m_pParallelPort->writeToControl( value );
+}
+
+
+void ParallelPortComponent::stepNonLogic()
+{
+ uchar status = m_pParallelPort->readFromRegister( ParallelPort::Status );
+ // Bits 0...2 in the Status register are not used
+ for ( int i = 3; i < 8; ++i )
+ m_pLogic[i + 8]->setHigh( status | (1 << i) );
+}
+
+
+void ParallelPortComponent::drawShape( QPainter & p )
+{
+ drawPortShape( p );
+}
diff --git a/src/electronics/components/parallelportcomponent.h b/src/electronics/components/parallelportcomponent.h
new file mode 100644
index 0000000..89ead80
--- /dev/null
+++ b/src/electronics/components/parallelportcomponent.h
@@ -0,0 +1,49 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef PARALLELPORTCOMPONENT_H
+#define PARALLELPORTCOMPONENT_H
+
+#include "logic.h"
+#include "component.h"
+
+class ParallelPort;
+
+/**
+@author David Saxton
+ */
+class ParallelPortComponent : public CallbackClass, public Component
+{
+ public:
+ ParallelPortComponent( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ParallelPortComponent();
+
+ virtual bool canFlip() const { return true; }
+ static Item * construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem * libraryItem();
+
+ virtual void stepNonLogic();
+ virtual bool doesStepNonLogic() const { return true; }
+
+ protected:
+ void initPort( const QString & port );
+ virtual void dataChanged();
+ virtual void drawShape( QPainter & p );
+
+ void dataCallback( bool );
+ void controlCallback( bool );
+
+ /// Registers: { Data[0...7], Status[0...5], 0[6...7], Control[0...4], 0[5...7] }
+ LogicOut * m_pLogic[24];
+
+ ParallelPort * m_pParallelPort;
+};
+
+#endif
diff --git a/src/electronics/components/piccomponent.cpp b/src/electronics/components/piccomponent.cpp
new file mode 100644
index 0000000..47320bb
--- /dev/null
+++ b/src/electronics/components/piccomponent.cpp
@@ -0,0 +1,437 @@
+/***************************************************************************
+ * Copyright (C) 2003-2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "config.h"
+#ifndef NO_GPSIM
+
+#include "canvasitemparts.h"
+#include "circuitdocument.h"
+#include "docmanager.h"
+#include "gpsimprocessor.h"
+#include "libraryitem.h"
+#include "logic.h"
+#include "ktechlab.h"
+#include "micropackage.h"
+#include "picinfo.h"
+#include "microlibrary.h"
+#include "piccomponent.h"
+#include "piccomponentpin.h"
+#include "projectmanager.h"
+
+#include <kdebug.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <qguardedptr.h>
+#include <qstringlist.h>
+
+#include "gpsim/ioports.h"
+#include "gpsim/pic-processor.h"
+
+const QString _def_PICComponent_fileName = i18n("<Enter location of PIC Program>");
+
+
+Item* PICComponent::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new PICComponent( (ICNDocument*)itemDocument, newItem, id );
+}
+
+
+LibraryItem* PICComponent::libraryItem()
+{
+ QStringList IDs;
+ IDs << "ec/pic" << "ec/picitem" << "ec/picitem_18pin";
+
+ return new LibraryItem(
+ IDs,
+ "PIC",
+ i18n("Integrated Circuits"),
+ "ic2.png",
+ LibraryItem::lit_component,
+ PICComponent::construct );
+}
+
+PICComponent::PICComponent( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, id ? id : "pic" )
+{
+ m_name = i18n("PIC Micro");
+ m_desc = i18n("The PIC component allows the simulation of a PIC program.<br><br>"
+ "The loadable PIC program must be one of the following formats:"
+ "<ul><li>Assembly (.asm)</li>"
+ "<li>FlowCode (.flowcode)</li>"
+ "<li>Symbol file (.cod)</li>"
+ "<li>Microbe (.microbe, .basic)</li>"
+ "<li>C source (.c)</li></ul>"
+ "Doubleclick on the PIC component to open up the program source file.<br><br>"
+ "If the program source file is of type assembly, then the the opened text file will automatically be linked to the simulation. "
+ "You can control the program from the text document using the debug controls.<br><br>"
+ "Explanation of buttons:"
+ "<ul><li>Play - Run the PIC program from the point at which it was paused, or from the start otherwise.</li>"
+ "<li>Pause - Pause the simulation at the current execution point.</li>"
+ "<li>Stop - Reset all parts of the simulation.</li>"
+ "<li>Reload - Reread the PIC program from disk and restart gpsim.</li></ul>");
+
+ m_bCreatedInitialPackage = false;
+ m_bLoadingProgram = false;
+ m_pGpsim = 0L;
+
+ addButton( "run", QRect(), KGlobal::iconLoader()->loadIcon( "player_play", KIcon::Small ) );
+ addButton( "pause", QRect(), KGlobal::iconLoader()->loadIcon( "player_pause", KIcon::Small ) );
+ addButton( "reset", QRect(), KGlobal::iconLoader()->loadIcon( "stop", KIcon::Small ) );
+ addButton( "reload", QRect(), KGlobal::iconLoader()->loadIcon( "reload", KIcon::Small ) );
+
+ if ( icnDocument->ktechlab() )
+ connect( icnDocument->ktechlab(), SIGNAL(recentFileAdded(const KURL &)), this, SLOT(slotUpdateFileList()) );
+
+ connect( ProjectManager::self(), SIGNAL(projectOpened()), this, SLOT(slotUpdateFileList()) );
+ connect( ProjectManager::self(), SIGNAL(projectClosed()), this, SLOT(slotUpdateFileList()) );
+ connect( ProjectManager::self(), SIGNAL(projectCreated()), this, SLOT(slotUpdateFileList()) );
+ connect( ProjectManager::self(), SIGNAL(subprojectCreated()), this, SLOT(slotUpdateFileList()) );
+ connect( ProjectManager::self(), SIGNAL(filesAdded()), this, SLOT(slotUpdateFileList()) );
+ connect( ProjectManager::self(), SIGNAL(filesRemoved()), this, SLOT(slotUpdateFileList()) );
+
+ createProperty( "program", Variant::Type::FileName );
+ property("program")->setCaption( i18n("Program") );
+ property("program")->setFilter("*.flowcode *.asm *.cod *.basic|All Supported Files\n*.flowcode|FlowCode (*.flowcode)\n*.cod|Symbol File (*.cod)\n*.asm|Assembly Code (*.asm)\n*.basic *.microbe|Microbe (*.basic, *.microbe)\n*.c|C (*.c)*|All Files");
+
+ // Used for restoring the pins on file loading before we have had a change
+ // to compile the PIC program
+ createProperty( "lastPackage", Variant::Type::String );
+ property("lastPackage")->setHidden( true );
+
+// //HACK This is to enable loading with pre-0.3 files (which didn't set a "lastPackage"
+// // property). This will allow a P16F84 PIC to be initialized (which agrees with pre-0.3
+// // behaviour), but it will also load it if
+
+ // This to allow loading of the PIC component from pre-0.3 files (which didn't set a
+ // "lastPackage" property).
+ if ( !newItem )
+ property("lastPackage")->setValue("P16F84");
+
+ slotUpdateFileList();
+ slotUpdateBtns();
+
+ initPackage( 0 );
+}
+
+
+PICComponent::~PICComponent()
+{
+ deletePICComponentPins();
+ delete m_pGpsim;
+}
+
+
+void PICComponent::dataChanged()
+{
+ initPIC(false);
+}
+
+
+void PICComponent::initPIC( bool forceReload )
+{
+ if ( !m_bCreatedInitialPackage )
+ {
+ // We are still being created, so other connectors will be expecting us to
+ // have grown pins soonish.
+ MicroInfo * microInfo = MicroLibrary::self()->microInfoWithID( dataString("lastPackage") );
+ if ( microInfo )
+ initPackage( microInfo );
+ }
+
+ QString newProgram = KURL( dataString("program") ).path();
+ bool newFile = (m_picFile != newProgram);
+ if ( !newFile && !forceReload )
+ return;
+
+ delete m_pGpsim;
+ m_pGpsim = 0L;
+
+ switch ( GpsimProcessor::isValidProgramFile(newProgram) )
+ {
+ case GpsimProcessor::DoesntExist:
+ if ( newProgram == _def_PICComponent_fileName && !newProgram.isEmpty() )
+ break;
+ KMessageBox::sorry( 0l, i18n("The file \"%1\" does not exist.").arg( newProgram ) );
+ m_picFile = QString::null;
+ break;
+
+ case GpsimProcessor::IncorrectType:
+ if ( newProgram == _def_PICComponent_fileName && !newProgram.isEmpty() )
+ break;
+ KMessageBox::sorry( 0L, i18n("\"%1\" is not a valid PIC program.\nThe file must exist, and the extension should be \".cod\", \".asm\", \".flowcode\", \".basic\", \".microbe\" or \".c\".\n\".hex\" is allowed, provided that there is a corresponding \".cod\" file.").arg(newProgram) );
+ m_picFile = QString::null;
+ break;
+
+ case GpsimProcessor::Valid:
+ m_picFile = newProgram;
+ m_symbolFile = createSymbolFile();
+ break;
+ }
+
+ slotUpdateBtns();
+}
+
+
+void PICComponent::deletePICComponentPins()
+{
+ const PICComponentPinMap::iterator picComponentMapEnd = m_picComponentPinMap.end();
+ for ( PICComponentPinMap::iterator it = m_picComponentPinMap.begin(); it != picComponentMapEnd; ++it )
+ delete it.data();
+ m_picComponentPinMap.clear();
+}
+
+
+void PICComponent::initPackage( MicroInfo * microInfo )
+{
+ MicroPackage * microPackage = microInfo ? microInfo->package() : 0l;
+
+ if ( microPackage )
+ {
+ m_bCreatedInitialPackage = true;
+
+ //BEGIN Get pin IDs
+ QStringList allPinIDs = microPackage->pinIDs();
+ QStringList ioPinIDs = microPackage->pinIDs( PicPin::type_bidir | PicPin::type_input | PicPin::type_open );
+
+ // Now, we make the unwanted pin ids blank, so a pin is not created for them
+ const QStringList::iterator allPinIDsEnd = allPinIDs.end();
+ for ( QStringList::iterator it = allPinIDs.begin(); it != allPinIDsEnd; ++it )
+ {
+ if ( !ioPinIDs.contains(*it) )
+ *it = "";
+ }
+ //END Get pin IDs
+
+
+ //BEGIN Remove old stuff
+ // Remove old text
+ TextMap textMapCopy = m_textMap;
+ const TextMap::iterator textMapEnd = textMapCopy.end();
+ for ( TextMap::iterator it = textMapCopy.begin(); it != textMapEnd; ++it )
+ removeDisplayText(it.key());
+
+ // Remove the old pins
+ deletePICComponentPins();
+
+ // Remove old nodes
+ NodeMap nodeMapCopy = m_nodeMap;
+ const NodeMap::iterator nodeMapEnd = nodeMapCopy.end();
+ for ( NodeMap::iterator it = nodeMapCopy.begin(); it != nodeMapEnd; ++it )
+ {
+ if ( !ioPinIDs.contains(it.key()) )
+ removeNode( it.key() );
+ }
+
+ removeElements();
+ //END Remove old stuff
+
+
+
+ //BEGIN Create new stuff
+ initDIPSymbol( allPinIDs, 80 );
+ initDIP(allPinIDs);
+
+ PicPinMap picPinMap = microPackage->pins( PicPin::type_bidir | PicPin::type_input | PicPin::type_open );
+ const PicPinMap::iterator picPinMapEnd = picPinMap.end();
+ for ( PicPinMap::iterator it = picPinMap.begin(); it != picPinMapEnd; ++it )
+ m_picComponentPinMap[it.key()] = new PICComponentPin( this, it.data() );
+ //END Create new stuff
+
+
+ removeDisplayText( "no_file" );
+ addDisplayText( "picid", QRect(offsetX(), offsetY()-16, width(), 16), microInfo->id() );
+ }
+ else
+ {
+ setSize( -48, -72, 96, 144 );
+ removeDisplayText( "picid" );
+ addDisplayText( "no_file", sizeRect(), i18n("(No\nprogram\nloaded)") );
+ }
+
+
+ //BEGIN Update button positions
+ int leftpos = (width()-88)/2+offsetX();
+ button("run")->setOriginalRect( QRect( leftpos, height()+4+offsetY(), 20, 20 ) );
+ button("pause")->setOriginalRect( QRect( leftpos+23, height()+4+offsetY(), 20, 20 ) );
+ button("reset")->setOriginalRect( QRect( leftpos+46, height()+4+offsetY(), 20, 20 ) );
+ button("reload")->setOriginalRect( QRect( leftpos+69, height()+4+offsetY(), 20, 20 ) );
+ updateAttachedPositioning();
+ //END Update button positions
+}
+
+
+void PICComponent::attachPICComponentPins()
+{
+ if ( !m_pGpsim || !m_pGpsim->picProcessor() )
+ return;
+
+ pic_processor * picProcessor = m_pGpsim->picProcessor();
+
+ const PICComponentPinMap::iterator end = m_picComponentPinMap.end();
+ for ( PICComponentPinMap::iterator it = m_picComponentPinMap.begin(); it != end; ++it )
+ it.data()->attach( picProcessor->get_pin( it.key() ) );
+}
+
+
+void PICComponent::slotUpdateFileList()
+{
+ QStringList preFileList;
+ if ( p_icnDocument && p_icnDocument->ktechlab() )
+ preFileList += p_icnDocument->ktechlab()->recentFiles();
+
+ QStringList fileList;
+
+ if ( ProjectInfo * info = ProjectManager::self()->currentProject() )
+ {
+ const KURL::List urls = info->childOutputURLs( ProjectItem::AllTypes, ProjectItem::ProgramOutput );
+ KURL::List::const_iterator urlsEnd = urls.end();
+ for ( KURL::List::const_iterator it = urls.begin(); it != urlsEnd; ++it )
+ fileList << (*it).path();
+ }
+
+ const QStringList::iterator end = preFileList.end();
+ for ( QStringList::iterator it = preFileList.begin(); it != end; ++it )
+ {
+ QString file = KURL(*it).path();
+ if ( (file.endsWith(".flowcode") || file.endsWith(".asm") || file.endsWith(".cod") || file.endsWith(".basic") || file.endsWith(".microbe") ) && !fileList.contains(file) ) {
+ fileList.append(file);
+ }
+ }
+
+ QString fileName = dataString("program");
+
+ property("program")->setAllowed(fileList);
+ property("program")->setValue( fileName.isEmpty() ? _def_PICComponent_fileName : fileName );
+}
+
+
+void PICComponent::buttonStateChanged( const QString &id, bool state )
+{
+ if (!state)
+ return;
+
+ if ( id == "reload" )
+ {
+ programReload();
+ return;
+ }
+
+ if (!m_pGpsim)
+ return;
+
+ if ( id == "run" )
+ m_pGpsim->setRunning(true);
+
+ else if ( id == "pause" )
+ m_pGpsim->setRunning(false);
+
+ else if ( id == "reset" )
+ {
+ m_pGpsim->reset();
+
+ // Set all pin outputs to low
+ const PICComponentPinMap::iterator end = m_picComponentPinMap.end();
+ for ( PICComponentPinMap::iterator it = m_picComponentPinMap.begin(); it != end; ++it )
+ it.data()->resetOutput();
+ }
+
+ slotUpdateBtns();
+}
+
+
+bool PICComponent::mouseDoubleClickEvent ( const EventInfo &eventInfo )
+{
+ Q_UNUSED(eventInfo);
+ if ( m_picFile.isEmpty() || (m_picFile == _def_PICComponent_fileName) )
+ return false;
+
+ (void) DocManager::self()->openURL(m_picFile);
+
+ return true;
+}
+
+
+QString PICComponent::createSymbolFile()
+{
+ m_bLoadingProgram = true;
+ slotUpdateBtns();
+
+ return GpsimProcessor::generateSymbolFile( dataString("program"), this, SLOT(slotCODCreationSucceeded()), SLOT(slotCODCreationFailed()) );
+}
+
+
+void PICComponent::slotCODCreationSucceeded()
+{
+ m_bLoadingProgram = false;
+
+ delete m_pGpsim;
+ m_pGpsim = new GpsimProcessor(m_symbolFile);
+
+ if ( m_pGpsim->codLoadStatus() == GpsimProcessor::CodSuccess )
+ {
+ MicroInfo * microInfo = m_pGpsim->microInfo();
+ property("lastPackage")->setValue( microInfo->id() );
+ initPackage( microInfo );
+
+ connect( m_pGpsim, SIGNAL(runningStatusChanged(bool )), this, SLOT(slotUpdateBtns()) );
+ attachPICComponentPins();
+ }
+
+ else
+ {
+ m_pGpsim->displayCodLoadStatus();
+ delete m_pGpsim;
+ m_pGpsim = 0l;
+ }
+
+ slotUpdateBtns();
+}
+
+
+void PICComponent::slotCODCreationFailed()
+{
+ m_bLoadingProgram = false;
+ slotUpdateBtns();
+}
+
+
+void PICComponent::programReload()
+{
+ delete m_pGpsim;
+ m_pGpsim = 0L;
+
+ initPIC(true);
+
+ slotUpdateBtns();
+}
+
+
+void PICComponent::slotUpdateBtns()
+{
+ // We can get called by the destruction of gpsim after our canvas has been set to NULL
+ if (!canvas())
+ return;
+
+ button("run")->setEnabled( m_pGpsim && !m_pGpsim->isRunning() );
+ button("pause")->setEnabled( m_pGpsim && m_pGpsim->isRunning() );
+ button("reset")->setEnabled( m_pGpsim );
+ button("reload")->setEnabled( !m_bLoadingProgram && (dataString("program") != _def_PICComponent_fileName) );
+
+ canvas()->setChanged( button("run")->boundingRect() );
+ canvas()->setChanged( button("pause")->boundingRect() );
+ canvas()->setChanged( button("reset")->boundingRect() );
+ canvas()->setChanged( button("reload")->boundingRect() );
+}
+
+
+#include "piccomponent.moc"
+
+#endif
diff --git a/src/electronics/components/piccomponent.h b/src/electronics/components/piccomponent.h
new file mode 100644
index 0000000..165fbf6
--- /dev/null
+++ b/src/electronics/components/piccomponent.h
@@ -0,0 +1,97 @@
+/***************************************************************************
+ * Copyright (C) 2003-2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef PICCOMPONENT_H
+#define PICCOMPONENT_H
+
+#include "config.h"
+#ifndef NO_GPSIM
+
+#include "component.h"
+
+#include <qguardedptr.h>
+#include <qmap.h>
+
+class Document;
+class ECNode;
+class GpsimProcessor;
+class IOPIN;
+class KTechlab;
+class MicroInfo;
+class MicroPackage;
+class PIC_IOPORT;
+class PICComponent;
+class PICComponentPin;
+class PicPin;
+class TextDocument;
+
+typedef QMap< int, PICComponentPin * > PICComponentPinMap;
+
+/**
+@short Electronic PIC device
+@author David Saxton
+*/
+class PICComponent : public Component
+{
+ Q_OBJECT
+ public:
+ PICComponent( ICNDocument * icnDocument, bool newItem, const char *id = 0L );
+ ~PICComponent();
+
+ virtual bool canFlip() const { return true; }
+ static Item * construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem * libraryItem();
+
+ virtual void buttonStateChanged( const QString &id, bool state );
+ virtual bool mouseDoubleClickEvent( const EventInfo &eventInfo );
+
+ void programReload();
+ /**
+ * Sets up the pins, text, etc for the given PIC type. If info is null,
+ * then a generic rectangle is displayed (used when no file has been
+ * loaded yet).
+ */
+ void initPackage( MicroInfo * info );
+
+ public slots:
+ void slotUpdateFileList();
+ void slotUpdateBtns();
+
+ protected slots:
+ void slotCODCreationSucceeded();
+ void slotCODCreationFailed();
+
+ protected:
+ /**
+ * Attaches all PICComponentPins to the current instance of gpsim.
+ */
+ void attachPICComponentPins();
+ void deletePICComponentPins();
+ /**
+ * Attempts to compile the program to a symbol file, and connects the assembly
+ * finish signal to loadGpsim
+ */
+ QString createSymbolFile();
+ virtual void dataChanged();
+ /**
+ * Initializes the PIC from the options the user has selected.
+ */
+ void initPIC( bool forceReload );
+
+ QGuardedPtr<GpsimProcessor> m_pGpsim;
+ QString m_picFile; ///< The input program that the user selected
+ QString m_symbolFile; ///< The symbol file that was generated from m_picFile
+ bool m_bLoadingProgram; ///< True between createSymbolFile being called and the file being created
+ PICComponentPinMap m_picComponentPinMap;
+ bool m_bCreatedInitialPackage; ///< Set true once the initial package is loaded; until then, will load a package from the lastPackage data
+};
+
+#endif
+#endif
diff --git a/src/electronics/components/piccomponentpin.cpp b/src/electronics/components/piccomponentpin.cpp
new file mode 100644
index 0000000..47ef6cb
--- /dev/null
+++ b/src/electronics/components/piccomponentpin.cpp
@@ -0,0 +1,172 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "config.h"
+#ifndef NO_GPSIM
+
+#include "micropackage.h"
+#include "piccomponent.h"
+#include "piccomponentpin.h"
+
+#include <kdebug.h>
+
+PICComponentPin::PICComponentPin( PICComponent * picComponent, PicPin picPin )
+ : m_id( picPin.pinID )
+{
+ m_gOutHigh = 0.0;
+ m_gOutLow = 0.0;
+ m_picPin = picPin;
+ m_pPICComponent = picComponent;
+ m_pLogicOut = 0l;
+ m_pLogicIn = 0l;
+ m_pIOPIN = 0l;
+ m_pStimulusNode = 0l;
+ Zth = 0.0;
+ Vth = 0.0;
+
+ switch ( picPin.type )
+ {
+ case PicPin::type_input:
+ {
+ m_pLogicIn = picComponent->createLogicIn( picComponent->ecNodeWithID(picPin.pinID) );
+ break;
+ }
+ case PicPin::type_bidir:
+ {
+ m_pLogicOut = picComponent->createLogicOut( picComponent->ecNodeWithID(picPin.pinID), false );
+ m_gOutHigh = 0.004;
+ m_gOutLow = 0.004;
+ break;
+ }
+ case PicPin::type_open:
+ {
+ m_pLogicOut = picComponent->createLogicOut( picComponent->ecNodeWithID(picPin.pinID), false );
+ m_pLogicOut->setOutputHighVoltage(0.0);
+ m_pLogicOut->setOutputHighConductance(0.0);
+ m_gOutHigh = 0.0;
+ m_gOutLow = 0.004;
+ break;
+ }
+ case PicPin::type_vss:
+ case PicPin::type_vdd:
+ case PicPin::type_mclr:
+ case PicPin::type_osc:
+ default:
+ break;
+ }
+
+ if (m_pLogicIn)
+ m_pLogicIn->setCallback( this, (CallbackPtr)(&PICComponentPin::logicCallback) );
+ if (m_pLogicOut)
+ m_pLogicOut->setCallback( this, (CallbackPtr)(&PICComponentPin::logicCallback) );
+}
+
+
+PICComponentPin::~PICComponentPin()
+{
+ delete m_pStimulusNode;
+}
+
+
+void PICComponentPin::attach( IOPIN * iopin )
+{
+ if (!iopin)
+ {
+ kdWarning() << k_funcinfo << " iopin is NULL" << endl;
+ return;
+ }
+
+ if (m_pStimulusNode)
+ {
+ kdWarning() << k_funcinfo << " Already have a node stimulus" << endl;
+ return;
+ }
+
+ if (m_pIOPIN)
+ {
+ kdWarning() << k_funcinfo << " Already have an iopin" << endl;
+ return;
+ }
+
+ m_pIOPIN = iopin;
+ m_pStimulusNode = new Stimulus_Node(m_id.ascii());
+ m_pStimulusNode->attach_stimulus(iopin);
+ m_pStimulusNode->attach_stimulus(this);
+
+
+ // We need to tell the iopin whether or not we are high
+ if (m_pLogicOut)
+ logicCallback( m_pLogicOut->isHigh() );
+ else if (m_pLogicIn)
+ logicCallback( m_pLogicIn->isHigh() );
+}
+
+
+double PICComponentPin::get_Vth( )
+{
+ if (!m_pIOPIN)
+ return 0.0;
+
+ if ( m_pIOPIN->get_direction() == IOPIN::DIR_INPUT )
+ return Vth;
+ else
+ return m_pIOPIN->get_Vth();
+}
+
+
+void PICComponentPin::set_nodeVoltage( double v )
+{
+ Q_UNUSED(v);
+
+ if ( !m_pLogicOut || !m_pIOPIN )
+ return;
+
+ if ( m_pIOPIN->get_direction() == IOPIN::DIR_INPUT )
+ {
+ m_pLogicOut->setOutputHighConductance(0.0);
+ m_pLogicOut->setOutputLowConductance(0.0);
+ return;
+ }
+
+ m_pLogicOut->setHigh( m_pIOPIN->getDrivingState() );
+ m_pLogicOut->setOutputHighConductance(m_gOutHigh);
+ m_pLogicOut->setOutputLowConductance(m_gOutLow);
+}
+
+
+void PICComponentPin::logicCallback( bool state )
+{
+ if (!m_pIOPIN)
+ return;
+
+ Vth = state ? 5e10 : 0;
+ bDrivingState = state;
+
+ if ( m_pIOPIN->get_direction() == IOPIN::DIR_INPUT )
+ {
+ Zth = 1e5;
+
+ m_pIOPIN->setDrivenState(state);
+ if (m_pStimulusNode)
+ m_pStimulusNode->update();
+ }
+ else
+ Zth = 0;
+}
+
+
+void PICComponentPin::resetOutput()
+{
+ if ( m_pLogicOut )
+ m_pLogicOut->setHigh( false );
+}
+
+#endif
+
diff --git a/src/electronics/components/piccomponentpin.h b/src/electronics/components/piccomponentpin.h
new file mode 100644
index 0000000..0fc433d
--- /dev/null
+++ b/src/electronics/components/piccomponentpin.h
@@ -0,0 +1,68 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef PICCOMPONENTPIN_H
+#define PICCOMPONENTPIN_H
+
+#include "config.h"
+#ifndef NO_GPSIM
+
+#include "logic.h"
+#include "gpsim/stimuli.h"
+
+#include <qstring.h>
+
+/**
+@short Controls a pin on the PIC component
+@author David Saxton
+ */
+class PICComponentPin : public CallbackClass, public stimulus
+{
+ public:
+ PICComponentPin( PICComponent * picComponent, PicPin picPin );
+ ~PICComponentPin();
+ /**
+ * Attach this to gpsim
+ */
+ void attach( IOPIN * iopin );
+ /**
+ * Called when the IOPIN this class is associated with changes state.
+ * Updates the associated LogicOut / LogicIn / etc according to what
+ * type of pin this is.
+ */
+ virtual void set_nodeVoltage( double v );
+ /**
+ * Called from our logic pin when the logic changes state.
+ */
+ void logicCallback( bool state );
+ /**
+ * Sets the output (if has one) to low. Called when the user stops the
+ * PIC.
+ */
+ void resetOutput();
+
+ virtual double get_Vth();
+
+ protected:
+ // Conductance of pin in different configurations
+ double m_gOutHigh;
+ double m_gOutLow;
+
+ PicPin m_picPin;
+ IOPIN * m_pIOPIN;
+ LogicOut * m_pLogicOut;
+ LogicIn * m_pLogicIn;
+ PICComponent * m_pPICComponent;
+ Stimulus_Node * m_pStimulusNode;
+ const QString m_id;
+};
+
+#endif
+#endif
diff --git a/src/electronics/components/probe.cpp b/src/electronics/components/probe.cpp
new file mode 100644
index 0000000..db6725e
--- /dev/null
+++ b/src/electronics/components/probe.cpp
@@ -0,0 +1,291 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "ecnode.h"
+#include "libraryitem.h"
+#include "logic.h"
+#include "pin.h"
+#include "probe.h" //HACK: This has to be included before the oscilloscope headers
+#include "oscilloscope.h"
+#include "oscilloscopedata.h"
+#include "simulator.h"
+#include "voltagesource.h"
+
+#include <klocale.h>
+#include <qpainter.h>
+
+//BEGIN class Probe
+Probe::Probe( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, id )
+{
+ p_probeData = 0l;
+ setSize( -16, -8, 32, 16 );
+
+ createProperty( "color", Variant::Type::Color );
+ property("color")->setCaption( i18n("Color") );
+ property("color")->setValue( Qt::black );
+}
+
+
+Probe::~ Probe()
+{
+ delete p_probeData;
+}
+
+
+void Probe::dataChanged()
+{
+ m_color = dataColor("color");
+ if (p_probeData)
+ p_probeData->setColor(m_color);
+ setChanged();
+}
+//END class Probe
+
+
+
+//BEGIN class FloatingProbe
+FloatingProbe::FloatingProbe( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Probe( icnDocument, newItem, id )
+{
+ p_probeData = m_pFloatingProbeData = static_cast<FloatingProbeData*>(registerProbe(this));
+ property("color")->setValue( p_probeData->color() );
+
+ createProperty( "scaling", Variant::Type::Select );
+ property("scaling")->setCaption( i18n("Scaling") );
+ property("scaling")->setAllowed( QStringList::split( ',', "Linear,Logarithmic") );
+ property("scaling")->setValue("Linear");
+ property("scaling")->setAdvanced( true );
+
+ createProperty( "upper_abs_value", Variant::Type::Double );
+ property("upper_abs_value")->setCaption( i18n("Upper Absolute Value") );
+ property("upper_abs_value")->setValue(10.0);
+ property("upper_abs_value")->setMinValue(0.0);
+ property("upper_abs_value")->setUnit("V");
+ property("upper_abs_value")->setAdvanced(true);
+
+ createProperty( "lower_abs_value", Variant::Type::Double );
+ property("lower_abs_value")->setCaption( i18n("Lower Absolute Value") );
+ property("lower_abs_value")->setValue(0.1);
+ property("lower_abs_value")->setMinValue(0.0);
+ property("lower_abs_value")->setUnit("V");
+ property("lower_abs_value")->setAdvanced(true);
+}
+
+
+FloatingProbe::~FloatingProbe()
+{
+}
+
+
+void FloatingProbe::dataChanged()
+{
+ Probe::dataChanged();
+
+ if ( dataString("scaling") == "Linear" )
+ m_pFloatingProbeData->setScaling( FloatingProbeData::Linear );
+ else
+ m_pFloatingProbeData->setScaling( FloatingProbeData::Logarithmic );
+
+ m_pFloatingProbeData->setUpperAbsValue( dataDouble("upper_abs_value") );
+ m_pFloatingProbeData->setLowerAbsValue( dataDouble("lower_abs_value") );
+}
+
+
+void FloatingProbe::drawShape( QPainter &p )
+{
+ initPainter(p);
+
+ int _x = int(x())-16;
+ int _y = int(y())-8;
+
+ p.drawRect( _x, _y, 32, 16 );
+
+ QPointArray bezier(4);
+
+ bezier[0] = QPoint( _x+4, _y+10 );
+ bezier[1] = QPoint( _x+12, _y-6 );
+ bezier[2] = QPoint( _x+20, _y+24 );
+ bezier[3] = QPoint( _x+28, _y+4 );
+
+ p.setPen( QPen( m_color, 2 ) );
+ p.drawCubicBezier(bezier);
+
+ deinitPainter(p);
+}
+//END class FloatingProbe
+
+
+
+//BEGIN class VoltageProbe
+Item* VoltageProbe::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new VoltageProbe( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* VoltageProbe::libraryItem()
+{
+ return new LibraryItem(
+ "ec/voltageprobe",
+ i18n("Voltage Probe"),
+ i18n("Outputs"),
+ "floatingprobe.png",
+ LibraryItem::lit_component,
+ VoltageProbe::construct );
+}
+
+VoltageProbe::VoltageProbe( ICNDocument *icnDocument, bool newItem, const char *id )
+ : FloatingProbe( icnDocument, newItem, id ? id : "voltageprobe" )
+{
+ m_name = i18n("Voltage Probe");
+ m_desc = i18n("Displays the voltage at the probe point on the oscilloscope.");
+
+ init1PinLeft();
+ init1PinRight();
+ m_pPin1 = m_pNNode[0]->pin();
+ m_pPin2 = m_pPNode[0]->pin();
+}
+
+
+VoltageProbe::~VoltageProbe()
+{
+}
+
+
+void VoltageProbe::stepNonLogic()
+{
+ m_pFloatingProbeData->addDataPoint( m_pPin1->voltage() - m_pPin2->voltage() );
+}
+//END class VoltageProbe
+
+
+
+//BEGIN class CurrentProbe
+Item* CurrentProbe::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new CurrentProbe( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* CurrentProbe::libraryItem()
+{
+ return new LibraryItem(
+ "ec/currentprobe",
+ i18n("Current Probe"),
+ i18n("Outputs"),
+ "floatingprobe.png",
+ LibraryItem::lit_component,
+ CurrentProbe::construct );
+}
+
+CurrentProbe::CurrentProbe( ICNDocument *icnDocument, bool newItem, const char *id )
+ : FloatingProbe( icnDocument, newItem, id ? id : "currentprobe" )
+{
+ m_name = i18n("Current Probe");
+ m_desc = i18n("Displays the current at the probe point on the oscilloscope.");
+
+
+ init1PinLeft(0);
+ init1PinRight(0);
+
+ m_voltageSource = createVoltageSource( m_pNNode[0], m_pPNode[0], 0. );
+}
+
+
+CurrentProbe::~CurrentProbe()
+{
+}
+
+
+void CurrentProbe::stepNonLogic()
+{
+ m_pFloatingProbeData->addDataPoint( -m_voltageSource->cbranchCurrent(0) );
+}
+//END class CurrentProbe
+
+
+
+
+//BEGIN class LogicProbe
+Item* LogicProbe::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new LogicProbe( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* LogicProbe::libraryItem()
+{
+ QStringList ids;
+ ids << "ec/probe" << "ec/logicprobe";
+ return new LibraryItem(
+ ids,
+ i18n("Logic Probe"),
+ i18n("Outputs"),
+ "logicprobe.png",
+ LibraryItem::lit_component,
+ LogicProbe::construct );
+}
+
+LogicProbe::LogicProbe( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Probe( icnDocument, newItem, id ? id : "probe" )
+{
+ m_name = i18n("Logic Probe");
+ m_desc = i18n("Connect this probe the the point in the circuit to measure the logic value. The output will be displayed in the Oscilloscope view.");
+
+ init1PinRight();
+ m_pIn = createLogicIn( m_pPNode[0] );
+
+ p_probeData = p_logicProbeData = static_cast<LogicProbeData*>(registerProbe(this));
+ property("color")->setValue( p_probeData->color() );
+
+ m_pSimulator = Simulator::self();
+ m_pIn->setCallback( this, (CallbackPtr)(&LogicProbe::logicCallback) );
+ logicCallback(false);
+}
+
+
+LogicProbe::~LogicProbe()
+{
+}
+
+
+void LogicProbe::logicCallback( bool value )
+{
+ p_logicProbeData->addDataPoint( LogicDataPoint( value, m_pSimulator->time() ) );
+}
+
+
+void LogicProbe::drawShape( QPainter &p )
+{
+ initPainter(p);
+
+ int _x = int(x())-16;
+ int _y = int(y())-8;
+
+ p.drawRect( _x, _y, 32, 16 );
+
+ p.setPen( QPen( m_color, 2 ) );
+
+ p.drawLine( _x+4, _y+11, _x+6, _y+11 );
+ p.drawLine( _x+6, _y+11, _x+6, _y+4 );
+ p.drawLine( _x+6, _y+4, _x+10, _y+4 );
+ p.drawLine( _x+10, _y+4, _x+10, _y+11 );
+ p.drawLine( _x+10, _y+11, _x+16, _y+11 );
+ p.drawLine( _x+16, _y+11, _x+16, _y+4 );
+ p.drawLine( _x+16, _y+4, _x+23, _y+4 );
+ p.drawLine( _x+23, _y+4, _x+23, _y+11 );
+ p.drawLine( _x+23, _y+11, _x+28, _y+11 );
+// p.drawLine( _x+23, _y+11, _x+26, _y+11 );
+// p.drawLine( _x+26, _y+11, _x+26, _y+4 );
+// p.drawLine( _x+26, _y+4, _x+28, _y+4 );
+
+ deinitPainter(p);
+}
+//END class LogicProbe
+
+
diff --git a/src/electronics/components/probe.h b/src/electronics/components/probe.h
new file mode 100644
index 0000000..9beb62e
--- /dev/null
+++ b/src/electronics/components/probe.h
@@ -0,0 +1,113 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef PROBE_H
+#define PROBE_H
+
+#include <component.h>
+
+class LogicProbeData;
+class ProbeData;
+class FloatingProbeData;
+
+/**
+@author David Saxton
+*/
+class Probe : public Component
+{
+ public:
+ Probe( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~Probe();
+
+ protected:
+ virtual void dataChanged();
+
+ ProbeData * p_probeData; // As obtained via registering with the oscilloscope
+ QColor m_color;
+};
+
+/**
+@author David Saxton
+ */
+class FloatingProbe : public Probe
+{
+ public:
+ FloatingProbe( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~FloatingProbe();
+
+ virtual bool doesStepNonLogic() const { return true; }
+
+ protected:
+ virtual void dataChanged();
+ virtual void drawShape( QPainter &p );
+
+ FloatingProbeData * m_pFloatingProbeData;
+};
+
+/**
+@author David Saxton
+ */
+class VoltageProbe : public FloatingProbe
+{
+ public:
+ VoltageProbe( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~VoltageProbe();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+ virtual void stepNonLogic();
+
+ protected:
+ Pin * m_pPin1;
+ Pin * m_pPin2;
+};
+
+/**
+@author David Saxton
+ */
+class CurrentProbe : public FloatingProbe
+{
+ public:
+ CurrentProbe( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~CurrentProbe();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+ virtual void stepNonLogic();
+
+ protected:
+ VoltageSource *m_voltageSource;
+};
+
+/**
+@author David Saxton
+ */
+class LogicProbe : public CallbackClass, public Probe
+{
+ public:
+ LogicProbe( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~LogicProbe();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+ void logicCallback( bool value );
+
+ protected:
+ virtual void drawShape( QPainter &p );
+
+ LogicProbeData * p_logicProbeData;
+ LogicIn * m_pIn;
+ Simulator * m_pSimulator;
+};
+
+#endif
diff --git a/src/electronics/components/pushswitch.cpp b/src/electronics/components/pushswitch.cpp
new file mode 100644
index 0000000..b7b38b7
--- /dev/null
+++ b/src/electronics/components/pushswitch.cpp
@@ -0,0 +1,204 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "canvasitemparts.h"
+#include "libraryitem.h"
+#include "pushswitch.h"
+#include "switch.h"
+
+#include <klocale.h>
+#include <qpainter.h>
+#include <qpixmap.h>
+#include <qpoint.h>
+#include <qpointarray.h>
+
+//BEGIN class ECPTBSwitch
+Item* ECPTBSwitch::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECPTBSwitch( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ECPTBSwitch::libraryItem()
+{
+ return new LibraryItem(
+ QString("ec/ptb_switch"),
+ i18n("Push-to-Break"),
+ i18n("Switches"),
+ "ptb.png",
+ LibraryItem::lit_component,
+ ECPTBSwitch::construct );
+}
+
+ECPTBSwitch::ECPTBSwitch( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, (id) ? id : "ptb_switch" )
+{
+ m_name = i18n("Push to Break");
+ setSize( -16, -16, 32, 24 );
+
+ addButton( "button", QRect( -16, 8, 32, 20 ), "" );
+
+ createProperty( "button_text", Variant::Type::String );
+ property("button_text")->setCaption( i18n("Button Text") );
+
+ Variant * v = createProperty( "bounce", Variant::Type::Bool );
+ v->setCaption( i18n("Bounce") );
+ v->setAdvanced(true);
+ v->setValue(false);
+
+ v = createProperty( "bounce_period", Variant::Type::Double );
+ v->setCaption( i18n("Bounce Period") );
+ v->setAdvanced(true);
+ v->setUnit("s");
+ v->setValue(5e-3);
+
+ init1PinLeft(0);
+ init1PinRight(0);
+
+ m_switch = createSwitch( m_pPNode[0], m_pNNode[0], false );
+ pressed = false;
+}
+
+ECPTBSwitch::~ECPTBSwitch()
+{
+}
+
+
+void ECPTBSwitch::dataChanged()
+{
+ button("button")->setText( dataString("button_text") );
+
+ bool bounce = dataBool("bounce");
+ int bouncePeriod_ms = int(dataDouble("bounce_period")*1e3);
+ m_switch->setBounce( bounce, bouncePeriod_ms );
+}
+
+
+void ECPTBSwitch::drawShape( QPainter &p )
+{
+ initPainter(p);
+
+ int _x = (int)x()-16;
+ int _y = (int)y()-8;
+ const int radius = 2;
+ const int _height = height()-8;
+
+ int dy = pressed ? 6 : 4;
+
+ p.drawLine( _x+width()/4, _y+dy, _x+(3*width())/4, _y+dy ); // Top horizontal line
+ p.drawLine( _x, _y+(_height/2)-radius+dy, _x+width(), _y+(_height/2)-radius+dy ); // Bottom horizontal line
+ p.drawLine( _x+width()/2, _y+dy, _x+width()/2, _y+(_height/2)-radius+dy ); // Vertical line
+
+ p.drawEllipse( _x, _y+(_height/2)-radius, 2*radius, 2*radius ); // Left circle
+ p.drawEllipse( _x+width()-2*radius+1, _y+(_height/2)-radius, 2*radius, 2*radius ); // Right circle
+
+ deinitPainter(p);
+}
+
+void ECPTBSwitch::buttonStateChanged( const QString &id, bool state )
+{
+ if ( id != "button" )
+ return;
+ m_switch->setState( state ? Switch::Open : Switch::Closed );
+ pressed = state;
+}
+//END class ECPTBSwitch
+
+
+//BEGIN class ECPTMSwitch
+Item* ECPTMSwitch::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECPTMSwitch( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ECPTMSwitch::libraryItem()
+{
+ return new LibraryItem(
+ QString("ec/ptm_switch"),
+ i18n("Push-to-Make"),
+ i18n("Switches"),
+ "ptm.png",
+ LibraryItem::lit_component,
+ ECPTMSwitch::construct );
+}
+
+ECPTMSwitch::ECPTMSwitch( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, (id) ? id : "ptm_switch" )
+{
+ m_name = i18n("Push to Make");
+ setSize( -16, -16, 32, 24 );
+
+ addButton( "button", QRect( -16, 8, 32, 20 ), "" );
+
+ createProperty( "button_text", Variant::Type::String );
+ property("button_text")->setCaption( i18n("Button Text") );
+
+ Variant * v = createProperty( "bounce", Variant::Type::Bool );
+ v->setCaption("Bounce");
+ v->setAdvanced(true);
+ v->setValue(false);
+
+ v = createProperty( "bounce_period", Variant::Type::Double );
+ v->setCaption("Bounce Period");
+ v->setAdvanced(true);
+ v->setUnit("s");
+ v->setValue(5e-3);
+
+ init1PinLeft(0);
+ init1PinRight(0);
+
+ m_switch = createSwitch( m_pPNode[0], m_pNNode[0], true );
+ pressed = false;
+}
+
+
+ECPTMSwitch::~ECPTMSwitch()
+{
+}
+
+
+void ECPTMSwitch::dataChanged()
+{
+ button("button")->setText( dataString("button_text") );
+
+ bool bounce = dataBool("bounce");
+ int bouncePeriod_ms = int(dataDouble("bounce_period")*1e3);
+ m_switch->setBounce( bounce, bouncePeriod_ms );
+}
+
+
+void ECPTMSwitch::drawShape( QPainter &p )
+{
+ initPainter(p);
+
+ int _x = (int)x()-16;
+ int _y = (int)y()-8;
+ const int radius = 2;
+ const int _height = height()-8;
+
+ int dy = pressed ? 1 : 3;
+
+ p.drawLine( _x+width()/4, _y-dy, _x+(3*width())/4, _y-dy ); // Top horizontal line
+ p.drawLine( _x, _y+(_height/2)-radius-dy, _x+width(), _y+(_height/2)-radius-dy ); // Bottom horizontal line
+ p.drawLine( _x+width()/2, _y-dy, _x+width()/2, _y+(_height/2)-radius-dy ); // Vertical line
+
+ p.drawEllipse( _x, _y+(_height/2)-radius, 2*radius, 2*radius ); // Left circle
+ p.drawEllipse( _x+width()-2*radius+1, _y+(_height/2)-radius, 2*radius, 2*radius ); // Right circle
+
+ deinitPainter(p);
+}
+
+void ECPTMSwitch::buttonStateChanged( const QString &id, bool state )
+{
+ if ( id != "button" ) return;
+ m_switch->setState( state ? Switch::Closed : Switch::Open );
+ pressed = state;
+}
+//END class ECPTMSwitch
+
diff --git a/src/electronics/components/pushswitch.h b/src/electronics/components/pushswitch.h
new file mode 100644
index 0000000..c22ea93
--- /dev/null
+++ b/src/electronics/components/pushswitch.h
@@ -0,0 +1,62 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef PUSHSWITCH_H
+#define PUSHSWITCH_H
+
+#include "component.h"
+
+/**
+@short Push-to-Break switch component
+@author David Saxton
+*/
+class ECPTBSwitch : public Component
+{
+public:
+ ECPTBSwitch( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECPTBSwitch();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+ virtual void buttonStateChanged( const QString &id, bool state );
+ virtual void dataChanged();
+
+private:
+ virtual void drawShape( QPainter &p );
+ Switch *m_switch;
+ bool pressed;
+};
+
+
+/**
+@short Push-to-make switch
+@author David Saxton
+*/
+class ECPTMSwitch : public Component
+{
+public:
+ ECPTMSwitch( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECPTMSwitch();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+ virtual void buttonStateChanged( const QString &id, bool state );
+ virtual void dataChanged();
+
+private:
+ virtual void drawShape( QPainter &p );
+ Switch *m_switch;
+ bool pressed;
+};
+
+
+#endif
diff --git a/src/electronics/components/ram.cpp b/src/electronics/components/ram.cpp
new file mode 100644
index 0000000..add745a
--- /dev/null
+++ b/src/electronics/components/ram.cpp
@@ -0,0 +1,232 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "libraryitem.h"
+#include "logic.h"
+#include "ram.h"
+#include "variant.h"
+
+#include <cmath>
+#include <klocale.h>
+
+Item* RAM::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new RAM( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* RAM::libraryItem()
+{
+ return new LibraryItem(
+ QString("ec/ram"),
+ i18n("RAM"),
+ i18n("Integrated Circuits"),
+ "ic2.png",
+ LibraryItem::lit_component,
+ RAM::construct
+ );
+}
+
+RAM::RAM( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, id ? id : "ram" )
+{
+ m_name = i18n("RAM");
+ m_desc = i18n("This RAM stores data as a collection of words; each of which contains <i>word size</i> bits of data.<br><br>To read data, set the CS (<i>chip select</i>) and the OE (<i>output enable</i>) pins high, and select the word using the address pins <i>A*</i>. The word is outputted on the data-out pins: <i>DO*</i>.<br><br>To write data, set the CS (<i>chip select</i>) and the WE (<i>write enable</i>) pins high, and select the address to write to with the <i>A*</i> pins. Write to the selected word using the data-in pins: <i>DI*</i>.<br><br>The <i>Address Size</i> is the number of bits that determine an address; so the total number of words stored will be 2^<sup><i>Address Size</i></sup>.");
+
+ m_data = 0l;
+ m_pCS = 0l;
+ m_pOE = 0l;
+ m_pWE = 0l;
+ m_wordSize = 0;
+ m_addressSize = 0;
+
+ createProperty( "wordSize", Variant::Type::Int );
+ property("wordSize")->setCaption( i18n("Word Size") );
+ property("wordSize")->setMinValue(1);
+ property("wordSize")->setMaxValue(256);
+ property("wordSize")->setValue(2);
+
+ createProperty( "addressSize", Variant::Type::Int );
+ property("addressSize")->setCaption( i18n("Address Size") );
+ property("addressSize")->setMinValue(1);
+ property("addressSize")->setMaxValue(32);
+ property("addressSize")->setValue(4);
+
+ m_data = createProperty( "data", Variant::Type::Raw )->value().asBitArray();
+}
+
+RAM::~RAM()
+{
+}
+
+
+void RAM::dataChanged()
+{
+ m_wordSize = dataInt("wordSize");
+ m_addressSize = dataInt("addressSize");
+
+ int newSize = int( m_wordSize * std::pow( 2., m_addressSize ) );
+ m_data.resize(newSize);
+
+ initPins();
+}
+
+
+void RAM::inStateChanged( bool newState )
+{
+ Q_UNUSED(newState);
+
+ bool cs = m_pCS->isHigh();
+ bool oe = m_pOE->isHigh();
+ bool we = m_pWE->isHigh();
+
+ if ( !cs || !oe )
+ {
+ for ( int i = 0; i < m_wordSize; ++i )
+ m_dataOut[i]->setHigh(false);
+ }
+
+ if ( !cs || (!oe && !we) )
+ return;
+
+ unsigned address = 0;
+ for ( int i = 0; i < m_addressSize; ++i )
+ address += (m_address[i]->isHigh() ? 1 : 0) << i;
+
+ if (we)
+ {
+ for ( int i = 0; i < m_wordSize; ++i )
+ m_data[ m_wordSize * address + i ] = m_dataIn[i]->isHigh();
+ }
+
+ if (oe)
+ {
+ for ( int i = 0; i < m_wordSize; ++i )
+ m_dataOut[i]->setHigh( m_data[ m_wordSize * address + i ] );
+ }
+}
+
+
+void RAM::initPins()
+{
+ int oldWordSize = m_dataIn.size();
+ int oldAddressSize = m_address.size();
+
+ int newWordSize = dataInt("wordSize");
+ int newAddressSize = dataInt("addressSize");
+
+ if ( newAddressSize == oldAddressSize &&
+ newWordSize == oldWordSize )
+ return;
+
+ QStringList leftPins; // Pins on left of IC
+ leftPins << "CS" << "OE" << "WE";
+ for ( int i = 0; i < newAddressSize; ++i )
+ leftPins << QString("A%1").arg( QString::number(i) );
+
+ QStringList rightPins; // Pins on right of IC
+ for ( unsigned i = newWordSize; i > 0; --i )
+ rightPins << QString("DI%1").arg( QString::number(i-1) );
+ for ( unsigned i = newWordSize; i > 0; --i )
+ rightPins << QString("DO%1").arg( QString::number(i-1) );
+
+ // Make pin lists of consistent sizes
+ for ( unsigned i = leftPins.size(); i < rightPins.size(); ++i )
+ leftPins.append("");
+ for ( unsigned i = rightPins.size(); i < leftPins.size(); ++i )
+ rightPins.prepend("");
+
+ QStringList pins = leftPins + rightPins;
+
+ initDIPSymbol( pins, 72 );
+ initDIP(pins);
+
+ ECNode *node;
+
+ if (!m_pCS)
+ {
+ node = ecNodeWithID("CS");
+ m_pCS = createLogicIn(node);
+ m_pCS->setCallback( this, (CallbackPtr)(&RAM::inStateChanged) );
+ }
+
+ if (!m_pOE)
+ {
+ node = ecNodeWithID("OE");
+ m_pOE = createLogicIn(node);
+ m_pOE->setCallback( this, (CallbackPtr)(&RAM::inStateChanged) );
+ }
+
+ if (!m_pWE)
+ {
+ node = ecNodeWithID("WE");
+ m_pWE = createLogicIn(node);
+ m_pWE->setCallback( this, (CallbackPtr)(&RAM::inStateChanged) );
+ }
+
+ if ( newWordSize > oldWordSize )
+ {
+ m_dataIn.resize(newWordSize);
+ m_dataOut.resize(newWordSize);
+
+ for ( int i = oldWordSize; i < newWordSize; ++i )
+ {
+ node = ecNodeWithID( QString("DI%1").arg( QString::number(i) ) );
+ m_dataIn.insert( i, createLogicIn(node) );
+ m_dataIn[i]->setCallback( this, (CallbackPtr)(&RAM::inStateChanged) );
+
+ node = ecNodeWithID( QString("DO%1").arg( QString::number(i) ) );
+ m_dataOut.insert( i, createLogicOut(node, false) );
+ }
+ }
+ else if ( newWordSize < oldWordSize )
+ {
+ for ( int i = newWordSize; i < oldWordSize; ++i )
+ {
+ QString id = QString("DO%1").arg( QString::number(i) );
+ removeDisplayText(id);
+ removeElement( m_dataIn[i], false );
+ removeNode(id);
+
+ id = QString("DI%1").arg( QString::number(i) );
+ removeDisplayText(id);
+ removeElement( m_dataOut[i], false );
+ removeNode(id);
+ }
+
+ m_dataIn.resize(newWordSize);
+ m_dataOut.resize(newWordSize);
+ }
+
+ if ( newAddressSize > oldAddressSize )
+ {
+ m_address.resize(newAddressSize);
+
+ for ( int i = oldAddressSize; i < newAddressSize; ++i )
+ {
+ node = ecNodeWithID( QString("A%1").arg( QString::number(i) ) );
+ m_address.insert( i, createLogicIn(node) );
+ m_address[i]->setCallback( this, (CallbackPtr)(&RAM::inStateChanged) );
+ }
+ }
+ else if ( newAddressSize < oldAddressSize )
+ {
+ for ( int i = newAddressSize; i < oldAddressSize; ++i )
+ {
+ QString id = QString("A%1").arg( QString::number(i) );
+ removeDisplayText(id);
+ removeElement( m_address[i], false );
+ removeNode(id);
+ }
+
+ m_address.resize(newAddressSize);
+ }
+}
+
+
diff --git a/src/electronics/components/ram.h b/src/electronics/components/ram.h
new file mode 100644
index 0000000..7b78ee9
--- /dev/null
+++ b/src/electronics/components/ram.h
@@ -0,0 +1,51 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef RAM_H
+#define RAM_H
+
+#include "component.h"
+#include "logic.h"
+
+#include <qbitarray.h>
+#include <qptrvector.h>
+
+/**
+@author David Saxton
+*/
+class RAM : public CallbackClass, public Component
+{
+ public:
+ RAM( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~RAM();
+
+ virtual bool canFlip() const { return true; }
+ static Item * construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem * libraryItem();
+
+ protected:
+ void initPins();
+ virtual void dataChanged();
+ void inStateChanged( bool newState );
+
+ QBitArray m_data;
+ LogicIn * m_pCS; // Chip select
+ LogicIn * m_pOE; // Output enable
+ LogicIn * m_pWE; // Write enable
+
+ int m_wordSize;
+ int m_addressSize;
+
+ QPtrVector<LogicIn> m_address;
+ QPtrVector<LogicIn> m_dataIn;
+ QPtrVector<LogicOut> m_dataOut;
+};
+
+#endif
diff --git a/src/electronics/components/resistordip.cpp b/src/electronics/components/resistordip.cpp
new file mode 100644
index 0000000..d2c5bdb
--- /dev/null
+++ b/src/electronics/components/resistordip.cpp
@@ -0,0 +1,132 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "libraryitem.h"
+#include "node.h"
+#include "resistance.h"
+#include "resistordip.h"
+
+#include <kiconloader.h>
+#include <klocale.h>
+#include <qpainter.h>
+
+Item* ResistorDIP::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ResistorDIP( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ResistorDIP::libraryItem()
+{
+ return new LibraryItem(
+ "ec/resistordip",
+ i18n("Resistor DIP"),
+ i18n("Discrete"),
+ "resistordip.png",
+ LibraryItem::lit_component,
+ ResistorDIP::construct
+ );
+}
+
+ResistorDIP::ResistorDIP( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, id ? id : "multiplexer" )
+{
+ m_name = i18n("Resistor DIP");
+ m_desc = i18n("Set of resistors with identical values in a Dual Inline Package.");
+
+ m_resistorCount = 0;
+ for ( int i=0; i<maxCount; ++i )
+ m_resistance[i] = 0l;
+
+ createProperty( "resistance", Variant::Type::Double );
+ property("resistance")->setCaption( i18n("Resistance") );
+ property("resistance")->setUnit( QChar(0x3a9) );
+ property("resistance")->setValue(1e4);
+ property("resistance")->setMinValue(1e-6);
+
+ createProperty( "count", Variant::Type::Int );
+ property("count")->setCaption( i18n("Count") );
+ property("count")->setMinValue(2);
+ property("count")->setMaxValue(maxCount);
+ property("count")->setValue(8);
+}
+
+ResistorDIP::~ResistorDIP()
+{
+}
+
+
+void ResistorDIP::dataChanged()
+{
+ initPins();
+ const double resistance = dataDouble("resistance");
+ for ( int i=0; i<m_resistorCount; ++i )
+ m_resistance[i]->setResistance(resistance);
+
+ const QString display = QString::number( resistance / getMultiplier(resistance), 'g', 3 ) + getNumberMag(resistance) + QChar(0x3a9);
+ addDisplayText( "res", QRect( offsetX(), offsetY()-16, 32, 12 ), display );
+}
+
+
+void ResistorDIP::initPins()
+{
+ const int count = dataInt("count");
+ const double resistance = dataDouble("resistance");
+
+ if ( count == m_resistorCount )
+ return;
+
+ if ( count < m_resistorCount )
+ {
+ for ( int i=count; i<m_resistorCount; ++i )
+ {
+ removeElement( m_resistance[i], false );
+ m_resistance[i] = 0l;
+ removeNode( "n"+QString::number(i) );
+ removeNode( "p"+QString::number(i) );
+ }
+ }
+ else
+ {
+ for ( int i=m_resistorCount; i<count; ++i )
+ {
+ const QString nid = "n"+QString::number(i);
+ const QString pid = "p"+QString::number(i);
+ m_resistance[i] = createResistance( createPin( -24, 0, 0, nid ), createPin( 24, 0, 180, pid ), resistance );
+ }
+ }
+ m_resistorCount = count;
+
+ setSize( -16, -count*8, 32, count*16, true );
+ updateDIPNodePositions();
+}
+
+
+void ResistorDIP::updateDIPNodePositions()
+{
+ for ( int i=0; i<m_resistorCount; ++i )
+ {
+ m_nodeMap["n"+QString::number(i)].y = offsetY() + 8 + 16*i;
+ m_nodeMap["p"+QString::number(i)].y = offsetY() + 8 + 16*i;
+ }
+ updateAttachedPositioning();
+}
+
+
+void ResistorDIP::drawShape( QPainter &p )
+{
+ int _x = int(x()+offsetX());
+ int _y = int(y()+offsetY());
+
+ initPainter(p);
+ for ( int i=0; i<m_resistorCount; ++i )
+ p.drawRect( _x, _y+16*i+2, 32, 12 );
+ deinitPainter(p);
+}
+
diff --git a/src/electronics/components/resistordip.h b/src/electronics/components/resistordip.h
new file mode 100644
index 0000000..ce1d03a
--- /dev/null
+++ b/src/electronics/components/resistordip.h
@@ -0,0 +1,43 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef RESISTORDIP_H
+#define RESISTORDIP_H
+
+#include "component.h"
+
+const int maxCount = 256;
+
+/**
+@author David Saxton
+*/
+class ResistorDIP : public Component
+{
+public:
+ ResistorDIP( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ResistorDIP();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+protected:
+ virtual void drawShape( QPainter &p );
+ void updateDIPNodePositions();
+ virtual void dataChanged();
+ /**
+ * Add / remove pins according to the number of inputs the user has requested
+ */
+ void initPins();
+
+ int m_resistorCount;
+ Resistance* m_resistance[maxCount];
+};
+
+#endif
diff --git a/src/electronics/components/rotoswitch.cpp b/src/electronics/components/rotoswitch.cpp
new file mode 100644
index 0000000..872714c
--- /dev/null
+++ b/src/electronics/components/rotoswitch.cpp
@@ -0,0 +1,317 @@
+/***************************************************************************
+ * Copyright (C) 2005 by John Myers *
+ * electronerd@electronerdia.net *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "rotoswitch.h"
+
+#include "canvasitemparts.h"
+#include "ecnode.h"
+#include "libraryitem.h"
+#include "switch.h"
+
+#include <klocale.h>
+#include <qpainter.h>
+#include <cmath>
+#include <assert.h>
+
+#include <kdebug.h>
+
+//BEGIN class ECRotoSwitch
+Item* ECRotoSwitch::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECRotoSwitch( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ECRotoSwitch::libraryItem()
+{
+ return new LibraryItem(
+ QString("ec/roto_switch"),
+ i18n("Rotary"),
+ i18n("Switches"),
+ "rotary.png",
+ LibraryItem::lit_component,
+ ECRotoSwitch::construct );
+}
+
+
+ECRotoSwitch::ECRotoSwitch( ICNDocument *icnDocument, bool newItem, const char *id )
+: Component( icnDocument, newItem, id ? id : "roto_switch" ),
+m_numPositions(0)
+{
+// m_name = i18n("Rotary Switch(WIP)");
+ m_name = i18n("Rotary Switch");
+ m_desc = i18n("Rotary Switch"); ///< \todo better description for rotoswitch
+ QPointArray pa;
+ pa.makeArc( -_pinInnerRadius, -_pinInnerRadius, 2*_pinInnerRadius, 2*_pinInnerRadius , 0, 16*360 );
+ setItemPoints( pa );
+ //setSize( -64, -64, 128, 128 );
+
+ //half the side length of the buttons
+ int buttonRadius = 10;
+ addButton( "go_left", QRect( -_pinOuterRadius/3-buttonRadius, _pinOuterRadius-3*buttonRadius, 2*buttonRadius, 2*buttonRadius ), "<", false );
+ addButton( "go_right", QRect(_pinOuterRadius/3-buttonRadius, _pinOuterRadius-3*buttonRadius, 2*buttonRadius, 2*buttonRadius ), ">", false );
+
+ /*Variant * v = createProperty( "button_map", Variant::Type::String );
+ v->setCaption( i18n("Button Map") );
+ v->setAdvanced(true);
+ const QString defButtonMap("SSSSSSSSSSSM");
+ v->setValue(defButtonMap);
+ */
+ Variant * v = createProperty( "num_positions", Variant::Type::Int );
+ v->setCaption( i18n("Number of Positions") );
+ v->setAdvanced(false);
+ v->setValue(6);
+ v->setMinValue(3);
+ m_inNode = createPin(0,height()/2,270,"in");
+
+ v = createProperty( "bounce", Variant::Type::Bool );
+ v->setCaption("Bounce");
+ v->setAdvanced(true);
+ v->setValue(false);
+
+
+ v = createProperty( "bounce_period", Variant::Type::Double );
+ v->setCaption("Bounce Period");
+ v->setAdvanced(true);
+ v->setUnit("s");
+ v->setValue(5e-3);
+
+
+ v = createProperty( "cur_position", Variant::Type::Int );
+ v->setHidden( true );
+ v->setValue( 0 );
+
+ //v = createProperty( "left_momentary", Variant::Type::Bool );
+ //v->setCaption(i18n("Left Momentary" ) );
+ //v->setValue(false);
+}
+
+
+ECRotoSwitch::~ECRotoSwitch()
+{
+}
+
+
+void ECRotoSwitch::dataChanged()
+{
+ bool bounce = dataBool("bounce");
+ int bouncePeriod_ms = int(dataDouble("bounce_period")*1e3);
+ m_curPosition = dataInt( "cur_position" );
+ setUpSwitches();
+ if(m_positions[m_curPosition].posSwitch->state() != Switch::Closed)
+ {
+ m_positions[m_curPosition].posSwitch->setState(Switch::Closed);
+ }
+ for(int i = 0; i < m_numPositions; i++)
+ {
+ m_positions[i].posSwitch->setBounce( bounce, bouncePeriod_ms );
+ }
+}
+
+inline int roundTo10(int a){return ((a/10)+(a%10<5?0:1))*10;}
+void ECRotoSwitch::drawShape( QPainter &p )
+{
+ initPainter(p);
+
+
+ int cx = static_cast<int>(x());
+ int cy = static_cast<int>(y());
+
+ const int rotorRadius = 5;
+
+
+ //draw the rotor
+ p.drawEllipse(cx - rotorRadius, cy-rotorRadius, 2*rotorRadius, 2*rotorRadius);
+ //and its connection
+ p.drawLine(cx, cy+rotorRadius, cx, cy+_pinInnerRadius);
+
+ //draw the output positions
+ double angleBetweenPositions = (4*M_PI/3)/(m_numPositions - 1);
+ //kdDebug() << "drawShape: " << bigRadius << " " << angleBetweenPositions << endl;
+
+ /// \internal \brief Round to the nearest multiple of 8
+#define round_8(a) (((a) > 0) ? int(((a)+4)/8)*8 : int(((a)-4)/8)*8)
+ for(int i = 0; i < m_numPositions ; i++)
+ {
+ double angle = (7*M_PI/6) - (i * angleBetweenPositions);
+ int contactX = static_cast<int>(_contactRingRadius * cos(angle));
+ int contactY = static_cast<int>(_contactRingRadius * sin(angle));
+
+ p.drawEllipse(cx+contactX-_contactRadius, cy-contactY-_contactRadius, 2*_contactRadius, 2*_contactRadius);
+ int pinX, pinY;
+ switch(m_positions[i].pinAngle)
+ {
+ case 180:
+ pinX = _pinInnerRadius;
+ pinY = round_8(contactY);
+ break;
+ case 90:
+ pinX = round_8(contactX);
+ pinY = _pinInnerRadius;
+ break;
+ case 0:
+ pinX = -_pinInnerRadius;
+ pinY = round_8(contactY);
+ break;
+ default:
+ assert(!"Bad pin angle");
+ }
+ p.drawLine(cx+contactX, cy-contactY, cx+pinX, cy-pinY);
+ //kdDebug() << contactX <<", "<< contactY <<endl;
+ }
+#undef round_8
+ //draw the connection to the selected position
+ double angle = (7*M_PI/6) - (m_curPosition * angleBetweenPositions);
+ int contactX = static_cast<int>(_contactRingRadius * cos(angle));
+ int contactY = static_cast<int>(_contactRingRadius * sin(angle));
+ int rotorX = static_cast<int>(rotorRadius * cos(angle));
+ int rotorY = static_cast<int>(rotorRadius * sin(angle));
+ p.drawLine(cx+rotorX, cy-rotorY, cx+contactX, cy-contactY);
+
+
+ deinitPainter(p);
+}
+
+void ECRotoSwitch::buttonStateChanged( const QString & id, bool state )
+{
+ SwitchPosition& curSP = m_positions[m_curPosition];
+ int nextPos = m_curPosition;
+ if(m_numPositions < 2)
+ {
+ return;
+ }
+ if(!state) //release
+ {
+ if(!curSP.isMomentary)
+ {
+ return;
+ }
+
+ if(m_curPosition == 0)
+ {
+ nextPos = m_curPosition + 1;
+ }
+ else if(m_curPosition == m_numPositions - 1)
+ {
+ nextPos = m_curPosition - 1;
+ }
+
+ }
+ else //press
+ {
+ if(id == "go_left" && m_curPosition > 0)
+ {
+ nextPos = m_curPosition - 1;
+ }
+ else if(id == "go_right" && m_curPosition < m_numPositions - 1)
+ {
+ nextPos = m_curPosition + 1;
+ }
+
+ }
+ if(nextPos != m_curPosition)
+ {
+ SwitchPosition& nextSP = m_positions[nextPos];
+
+ curSP.posSwitch->setState(Switch::Open);
+ nextSP.posSwitch->setState(Switch::Closed);
+
+ m_curPosition = nextPos;
+
+ property( "cur_position" )->setValue( m_curPosition );
+ }
+}
+
+
+/*!
+ Set up the switches according to the button_map
+ *
+ *
+ */
+void ECRotoSwitch::setUpSwitches()
+{
+ if( dataInt("num_positions") == m_numPositions )
+ {
+ // number of positions didn't change, so we don't have to do anything.
+ return;
+ }
+ //this uses the _old_ value of m_numPositions!
+ for(int i=0; i<m_numPositions; i++)
+ {
+ SwitchPosition& sp = m_positions[i];
+ QString pinName = QString("pin_%1").arg(i);
+ removeNode(pinName);
+ removeSwitch(sp.posSwitch);
+ }
+
+ m_numPositions = dataInt("num_positions");
+ if(m_curPosition >= m_numPositions )
+ {
+ setActivePosition( m_numPositions - 1 );
+ }
+ m_positions.clear();///\todo readjust old pins
+ m_positions.reserve(m_numPositions);
+ double angleBetweenPositions = (4*M_PI/3)/(m_numPositions - 1);
+ //kdDebug() << "setUpSwitches: " << bigRadius << " " << angleBetweenPositions << endl;
+ for( int i = 0; i < m_numPositions; i++)
+ {
+ double angle = (7*M_PI/6) - (i * angleBetweenPositions);
+ int contactX = static_cast<int>(_contactRingRadius * cos(angle));
+ int contactY = static_cast<int>(_contactRingRadius * sin(angle));
+
+ SwitchPosition sp;
+ if(angle > 3*M_PI/4)
+ {
+ sp.pinAngle = 0;
+ contactX = -_pinOuterRadius;
+ }
+ else if(angle > M_PI/4)
+ {
+ sp.pinAngle = 90;
+ contactY=_pinOuterRadius;
+ }
+ else
+ {
+ sp.pinAngle = 180;
+ contactX = _pinOuterRadius;
+ }
+ // kdDebug() << contactX <<", "<< contactY <<endl;
+
+
+ sp.node = createPin(contactX,-contactY,sp.pinAngle,QString("pin_%1").arg(i));
+ sp.posSwitch = createSwitch(m_inNode, sp.node, true);
+ sp.isMomentary = false;//(map[i] == 'M');
+ m_positions.push_back(sp);
+ }
+ updateAttachedPositioning();
+
+ // redraw ourself
+ setChanged();
+}
+
+/*!
+ * Set the current position to \c newPosition updating the state of the switch.
+ * \c m_curPosition must reference a valid position to switch away from
+ *
+ * \param newPosition the position to switch to
+ */
+void ECRotoSwitch::setActivePosition(int newPosition)
+{
+ SwitchPosition& curSP = m_positions[m_curPosition];
+ SwitchPosition& nextSP = m_positions[newPosition];
+
+ curSP.posSwitch->setState(Switch::Open);
+ nextSP.posSwitch->setState(Switch::Closed);
+
+ m_curPosition = newPosition;
+
+ property( "cur_position" )->setValue( m_curPosition );
+
+}
+//END class ECRotoSwitch
diff --git a/src/electronics/components/rotoswitch.h b/src/electronics/components/rotoswitch.h
new file mode 100644
index 0000000..909c0ea
--- /dev/null
+++ b/src/electronics/components/rotoswitch.h
@@ -0,0 +1,70 @@
+/***************************************************************************
+ * Copyright (C) 2005 by John Myers *
+ * electronerd@electronerdia.net *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef ROTOSWITCH_H
+#define ROTOSWITCH_H
+
+#include "component.h"
+#include <qvaluevector.h>
+
+struct SwitchPosition
+{
+ ECNode* node;
+ Switch* posSwitch;
+ bool isMomentary;
+ int pinAngle;
+};
+
+/**
+ * A rotary switch
+ * \author John Myers
+ */
+class ECRotoSwitch : public Component
+{
+public:
+ ECRotoSwitch( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECRotoSwitch();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+ virtual void buttonStateChanged( const QString &id, bool state );
+ virtual void dataChanged();
+
+private:
+ virtual void drawShape( QPainter &p );
+
+ int m_numPositions;
+ int m_curPosition;
+
+ ///Half the total width of the component including pins
+ static const int _pinOuterRadius = 64;
+ ///The width of the pins
+ static const int _pinWidth = 8;
+ ///the radius of the circle centered at the origin and tangent to the inner edge of the rows of pins
+ static const int _pinInnerRadius = _pinOuterRadius - _pinWidth;
+ ///gap between pins and contact circles
+ static const int _wireGap = 7;
+ ///The radius of the largest circle tangent to the pin circles
+ static const int _contactOuterRadius = _pinInnerRadius - _wireGap;
+ ///The radius of the circles used to show positions
+ static const int _contactRadius = 2;
+ ///The radius of the ring of positions
+ static const int _contactRingRadius = _contactOuterRadius - _contactRadius;
+
+ QValueVector<SwitchPosition> m_positions;
+ ECNode* m_inNode;
+
+protected:
+ void setUpSwitches();
+protected:
+ void setActivePosition(int newPosition);
+};
+#endif //ROTOSWITCH_H
diff --git a/src/electronics/components/serialportcomponent.cpp b/src/electronics/components/serialportcomponent.cpp
new file mode 100644
index 0000000..c8e6a4e
--- /dev/null
+++ b/src/electronics/components/serialportcomponent.cpp
@@ -0,0 +1,242 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "port.h"
+#include "serialportcomponent.h"
+
+#include "ecnode.h"
+#include "itemdocument.h"
+#include "libraryitem.h"
+#include "pin.h"
+#include "resistance.h"
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <qpainter.h>
+
+#include <cmath>
+#include <termios.h>
+
+Item* SerialPortComponent::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new SerialPortComponent( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* SerialPortComponent::libraryItem()
+{
+ return new LibraryItem(
+ "ec/serial_port",
+ i18n("Serial Port"),
+ i18n("Connections"),
+ "ic1.png",
+ LibraryItem::lit_component,
+ SerialPortComponent::construct
+ );
+}
+
+SerialPortComponent::SerialPortComponent( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, id ? id : "serial_port" )
+{
+ m_name = i18n("Serial Port");
+ m_desc = i18n("Interface to a serial port. The pins are:<br>"
+ "<ul>"
+ "<li><b>CD</b> - Carrier Detect (control; output)</li>"
+ "<li><b>RD</b> - Received Data (data; output)</li>"
+ "<li><b>TD</b> - Transmitted Data (data; input)</li>"
+ "<li><b>DTR</b> - Data Terminal Ready (control; input)</li>"
+ "<li><b>GND</b> - Signal Ground (ground)</li>"
+ "<li><b>DSR</b> - Data Set Ready (control; input)</li>"
+ "<li><b>RTS</b> - Request to Send (control; input)</li>"
+ "<li><b>CTS</b> - Clear to Send (control; output)</li>"
+ "<li><b>RI</b> - Ring Indicator (control; output)</li>"
+ "</ul>");
+
+ QPointArray pa( 4 );
+ pa[0] = QPoint( -32, -48 );
+ pa[1] = QPoint( 32, -40 );
+ pa[2] = QPoint( 32, 40 );
+ pa[3] = QPoint( -32, 48 );
+
+ setItemPoints( pa );
+
+ m_pSerialPort = new SerialPort();
+
+ ECNode * pin = 0;
+
+ // Works
+ pin = createPin( -40, 32, 0, "CD" );
+ addDisplayText( "CD", QRect( -28, 24, 28, 16 ), "CD", true, Qt::AlignLeft | Qt::AlignVCenter );
+ m_pCD = createLogicOut( pin, false );
+
+ // Doesn't work
+// pin = createPin( -40, 16, 0, "RD" );
+ addDisplayText( "RD", QRect( -28, 8, 28, 16 ), "RD", true, Qt::AlignLeft | Qt::AlignVCenter );
+// m_pRD = createLogicOut( pin, false );
+
+ // Works
+ pin = createPin( -40, 0, 0, "TD" );
+ addDisplayText( "TD", QRect( -28, -8, 28, 16 ), "TD", true, Qt::AlignLeft | Qt::AlignVCenter );
+ m_pTD = createLogicIn( pin);
+ m_pTD->setCallback( this, (CallbackPtr)(&SerialPortComponent::tdCallback) );
+
+ // Works
+ pin = createPin( -40, -16, 0, "DTR" );
+ addDisplayText( "DTR", QRect( -28, -24, 28, 16 ), "DTR", true, Qt::AlignLeft | Qt::AlignVCenter );
+ m_pDTR = createLogicIn( pin );
+ m_pDTR->setCallback( this, (CallbackPtr)(&SerialPortComponent::dtrCallback) );
+
+ // N/A
+ pin = createPin( -40, -32, 0, "GND" );
+ addDisplayText( "GND", QRect( -28, -40, 28, 16 ), "GND", true, Qt::AlignLeft | Qt::AlignVCenter );
+ pin->pin()->setGroundType( Pin::gt_always );
+
+ // Doesn't work
+// pin = createPin( 40, 24, 180, "DSR" );
+ addDisplayText( "DSR", QRect( 0, 16, 28, 16 ), "DSR", true, Qt::AlignRight | Qt::AlignVCenter );
+// m_pDSR = createLogicIn( pin );
+// m_pDSR->setCallback( this, (CallbackPtr)(&SerialPortComponent::dsrCallback) );
+
+ // Doesn't work
+// pin = createPin( 40, 8, 180, "RTS" );
+ addDisplayText( "RTS", QRect( 0, 0, 28, 16 ), "RTS", true, Qt::AlignRight | Qt::AlignVCenter );
+// m_pRTS = createLogicIn( pin );
+// m_pRTS->setCallback( this, (CallbackPtr)(&SerialPortComponent::rtsCallback) );
+
+ // Works
+ pin = createPin( 40, -8, 180, "CTS" );
+ addDisplayText( "CTS", QRect( 0, -16, 28, 16 ), "CTS", true, Qt::AlignRight | Qt::AlignVCenter );
+ m_pCTS = createLogicOut( pin, false );
+
+ // Works
+ pin = createPin( 40, -24, 180, "RI" );
+ addDisplayText( "RI", QRect( 0, -32, 28, 16 ), "RI", true, Qt::AlignRight | Qt::AlignVCenter );
+ m_pRI = createLogicOut( pin, false );
+
+ Variant * v = createProperty( "port", Variant::Type::Combo );
+ v->setAllowed( SerialPort::ports( Port::ExistsAndRW ) );
+ v->setCaption( i18n("Port") );
+
+// v = createProperty( "baudRate", Variant::Type::Select );
+// v->setAllowed( QStringList::split( ",", "B0,B50,B75,B110,B134,B150,B200,B300,B600,B1200,B1800,B2400,B4800,B9600,B19200,B38400" ) );
+// v->setCaption( i18n("Baud rate") );
+// v->setValue("B9600");
+}
+
+
+SerialPortComponent::~SerialPortComponent()
+{
+ delete m_pSerialPort;
+}
+
+
+void SerialPortComponent::dataChanged()
+{
+#if 0
+ QString baudString = dataString("baudRate");
+ unsigned baudRate = 0;
+
+ if ( baudString == "B0" )
+ baudRate = B0;
+ else if ( baudString == "B50" )
+ baudRate = B50;
+ else if ( baudString == "B75" )
+ baudRate = B75;
+ else if ( baudString == "B110" )
+ baudRate = B110;
+ else if ( baudString == "B134" )
+ baudRate = B134;
+ else if ( baudString == "B150" )
+ baudRate = B150;
+ else if ( baudString == "B200" )
+ baudRate = B200;
+ else if ( baudString == "B300" )
+ baudRate = B300;
+ else if ( baudString == "B600" )
+ baudRate = B600;
+ else if ( baudString == "B1200" )
+ baudRate = B1200;
+ else if ( baudString == "B1800" )
+ baudRate = B1800;
+ else if ( baudString == "B2400" )
+ baudRate = B2400;
+ else if ( baudString == "B4800" )
+ baudRate = B4800;
+ else if ( baudString == "B9600" )
+ baudRate = B9600;
+ else if ( baudString == "B19200" )
+ baudRate = B19200;
+ else if ( baudString == "B38400" )
+ baudRate = B38400;
+ else
+ {
+ kdError() << k_funcinfo << "Unknown baud rate = \""<<baudString<<"\""<<endl;
+ return;
+ }
+
+ initPort( dataString("port"), baudRate );
+#endif
+
+ initPort( dataString("port"), B200 );
+}
+
+
+void SerialPortComponent::initPort( const QString & port, unsigned baudRate )
+{
+ if ( port.isEmpty() )
+ {
+ m_pSerialPort->closePort();
+ return;
+ }
+
+ if ( ! m_pSerialPort->openPort( port, baudRate ) )
+ {
+ p_itemDocument->canvas()->setMessage( i18n("Could not open port %1").arg( port ) );
+ return;
+ }
+}
+
+
+void SerialPortComponent::stepNonLogic()
+{
+ m_pCD->setHigh( m_pSerialPort->pinState( SerialPort::CD ) );
+// m_pRD->setHigh( m_pSerialPort->pinState( SerialPort::RD ) );
+ m_pCTS->setHigh( m_pSerialPort->pinState( SerialPort::CTS ) );
+ m_pRI->setHigh( m_pSerialPort->pinState( SerialPort::RI ) );
+}
+
+
+void SerialPortComponent::tdCallback( bool isHigh )
+{
+ m_pSerialPort->setPinState( SerialPort::TD, isHigh );
+}
+
+
+void SerialPortComponent::dtrCallback( bool isHigh )
+{
+ m_pSerialPort->setPinState( SerialPort::DTR, isHigh );
+}
+
+
+void SerialPortComponent::dsrCallback( bool isHigh )
+{
+ m_pSerialPort->setPinState( SerialPort::DSR, isHigh );
+}
+
+
+void SerialPortComponent::rtsCallback( bool isHigh )
+{
+ m_pSerialPort->setPinState( SerialPort::RTS, isHigh );
+}
+
+
+void SerialPortComponent::drawShape( QPainter & p )
+{
+ drawPortShape( p );
+}
diff --git a/src/electronics/components/serialportcomponent.h b/src/electronics/components/serialportcomponent.h
new file mode 100644
index 0000000..4f9bc9a
--- /dev/null
+++ b/src/electronics/components/serialportcomponent.h
@@ -0,0 +1,61 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef SERIALPORTCOMPONENT_H
+#define SERIALPORTCOMPONENT_H
+
+#include "logic.h"
+#include "component.h"
+
+class SerialPort;
+
+/**
+@author David Saxton
+*/
+class SerialPortComponent : public CallbackClass, public Component
+{
+ public:
+ SerialPortComponent( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~SerialPortComponent();
+
+ virtual bool canFlip() const { return true; }
+ static Item * construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem * libraryItem();
+
+ virtual void stepNonLogic();
+ virtual bool doesStepNonLogic() const { return true; }
+
+ protected:
+ /**
+ * @param baudRate as defined in <bits/termios.h>
+ */
+ void initPort( const QString & port, unsigned baudRate );
+ virtual void dataChanged();
+ virtual void drawShape( QPainter & p );
+
+ void tdCallback( bool isHigh );
+ void dtrCallback( bool isHigh );
+ void dsrCallback( bool isHigh );
+ void rtsCallback( bool isHigh );
+
+ LogicIn * m_pTD;
+ LogicIn * m_pDTR;
+// LogicIn * m_pDSR;
+// LogicIn * m_pRTS;
+
+ LogicOut * m_pCD;
+// LogicOut * m_pRD;
+ LogicOut * m_pCTS;
+ LogicOut * m_pRI;
+
+ SerialPort * m_pSerialPort;
+};
+
+#endif
diff --git a/src/electronics/components/toggleswitch.cpp b/src/electronics/components/toggleswitch.cpp
new file mode 100644
index 0000000..4efe9ab
--- /dev/null
+++ b/src/electronics/components/toggleswitch.cpp
@@ -0,0 +1,407 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "toggleswitch.h"
+
+#include "canvasitemparts.h"
+#include "ecnode.h"
+#include "libraryitem.h"
+#include "switch.h"
+
+#include <klocale.h>
+#include <qpainter.h>
+
+//BEGIN class ECDPDT
+Item* ECDPDT::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECDPDT( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ECDPDT::libraryItem()
+{
+ return new LibraryItem(
+ QString("ec/dpdt_toggle"),
+ i18n("DPDT"),
+ i18n("Switches"),
+ "dpdt.png",
+ LibraryItem::lit_component,
+ ECDPDT::construct );
+}
+
+
+ECDPDT::ECDPDT( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, id ? id : "dpdt_toggle" )
+{
+ m_name = i18n("DPDT Toggle");
+ m_desc = i18n("Double-Pole Double-Throw switch.");
+ setSize( -16, -32, 32, 64 );
+
+ addButton( "button", QRect( -16, 32, 32, 20 ), "", true );
+
+ createProperty( "button_text", Variant::Type::String );
+ property("button_text")->setCaption( i18n("Button Text") );
+
+ Variant * v = createProperty( "bounce", Variant::Type::Bool );
+ v->setCaption("Bounce");
+ v->setAdvanced(true);
+ v->setValue(false);
+
+ v = createProperty( "bounce_period", Variant::Type::Double );
+ v->setCaption("Bounce Period");
+ v->setAdvanced(true);
+ v->setUnit("s");
+ v->setValue(5e-3);
+
+ init4PinRight( -24, -8, 8, 24 );
+
+ init2PinLeft( -16, 16 );
+
+ m_switch1 = createSwitch( m_pNNode[0], m_pPNode[0], false );
+ m_switch2 = createSwitch( m_pNNode[0], m_pPNode[1], true );
+ m_switch3 = createSwitch( m_pNNode[1], m_pPNode[2], false );
+ m_switch4 = createSwitch( m_pNNode[1], m_pPNode[3], true );
+ pressed = false;
+}
+
+
+ECDPDT::~ECDPDT()
+{
+}
+
+
+void ECDPDT::dataChanged()
+{
+ button("button")->setText( dataString("button_text") );
+
+ bool bounce = dataBool("bounce");
+ int bouncePeriod_ms = int(dataDouble("bounce_period")*1e3);
+
+ m_switch1->setBounce( bounce, bouncePeriod_ms );
+ m_switch2->setBounce( bounce, bouncePeriod_ms );
+ m_switch3->setBounce( bounce, bouncePeriod_ms );
+ m_switch4->setBounce( bounce, bouncePeriod_ms );
+}
+
+
+void ECDPDT::drawShape( QPainter &p )
+{
+ initPainter(p);
+
+ int _x = (int)x()-16;
+ int _y = (int)y()-32;
+ const int radius = 2;
+
+ p.drawEllipse( _x, _y+15, 2*radius, 2*radius );
+ p.drawEllipse( _x, _y+47, 2*radius, 2*radius );
+ p.drawEllipse( _x+width()-2*radius+1, _y+7, 2*radius, 2*radius );
+ p.drawEllipse( _x+width()-2*radius+1, _y+23, 2*radius, 2*radius );
+ p.drawEllipse( _x+width()-2*radius+1, _y+39, 2*radius, 2*radius );
+ p.drawEllipse( _x+width()-2*radius+1, _y+55, 2*radius, 2*radius );
+
+ const int dy = pressed ? 6 : -6;
+
+ p.drawLine( _x+2*radius, _y+16, _x+width()-2*radius+2, _y+16+dy );
+ p.drawLine( _x+2*radius, _y+48, _x+width()-2*radius+2, _y+48+dy );
+
+ deinitPainter(p);
+}
+
+void ECDPDT::buttonStateChanged( const QString &, bool state )
+{
+ pressed = state;
+ m_switch1->setState( state ? Switch::Open : Switch::Closed );
+ m_switch2->setState( state ? Switch::Closed : Switch::Open );
+ m_switch3->setState( state ? Switch::Open : Switch::Closed );
+ m_switch4->setState( state ? Switch::Closed : Switch::Open );
+}
+//END class ECDPDT
+
+
+//BEGIN class ECDPST
+Item* ECDPST::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECDPST( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ECDPST::libraryItem()
+{
+ return new LibraryItem(
+ QString("ec/dpst_toggle"),
+ i18n("DPST"),
+ i18n("Switches"),
+ "dpst.png",
+ LibraryItem::lit_component,
+ ECDPST::construct );
+}
+
+ECDPST::ECDPST( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, (id) ? id : "dpst_toggle" )
+{
+ m_name = i18n("DPST Toggle");
+ m_desc = i18n("Double-Pole Single-Throw switch.");
+ setSize( -16, -16, 32, 32 );
+
+ addButton( "button", QRect( -16, 16, 32, 20 ), "", true );
+
+ createProperty( "button_text", Variant::Type::String );
+ property("button_text")->setCaption( i18n("Button Text") );
+
+ Variant * v = createProperty( "bounce", Variant::Type::Bool );
+ v->setCaption("Bounce");
+ v->setAdvanced(true);
+ v->setValue(false);
+
+ v = createProperty( "bounce_period", Variant::Type::Double );
+ v->setCaption("Bounce Period");
+ v->setAdvanced(true);
+ v->setUnit("s");
+ v->setValue(5e-3);
+
+ init2PinLeft( -8, 8 );
+ init2PinRight( -8, 8 );
+
+ m_switch1 = createSwitch( m_pPNode[0], m_pNNode[0], true );
+ m_switch2 = createSwitch( m_pPNode[1], m_pNNode[1], true );
+ pressed = false;
+}
+
+
+ECDPST::~ECDPST()
+{
+}
+
+
+void ECDPST::dataChanged()
+{
+ button("button")->setText( dataString("button_text") );
+
+ bool bounce = dataBool("bounce");
+ int bouncePeriod_ms = int(dataDouble("bounce_period")*1e3);
+
+ m_switch1->setBounce( bounce, bouncePeriod_ms );
+ m_switch2->setBounce( bounce, bouncePeriod_ms );
+}
+
+
+void ECDPST::drawShape( QPainter &p )
+{
+ initPainter(p);
+
+ int _x = (int)x()-16;
+ int _y = (int)y()-16;
+ const int radius = 2;
+
+ p.drawEllipse( _x, _y+6, 2*radius, 2*radius );
+ p.drawEllipse( _x, _y+22, 2*radius, 2*radius );
+ p.drawEllipse( _x+width()-2*radius+1, _y+6, 2*radius, 2*radius );
+ p.drawEllipse( _x+width()-2*radius+1, _y+22, 2*radius, 2*radius );
+
+ const int dy = pressed ? 6 : 0;
+
+ p.drawLine( _x+2*radius,_y+7,_x+width()-2*radius,_y+1+dy );
+ p.drawLine( _x+2*radius,_y+24,_x+width()-2*radius,_y+18+dy );
+
+ deinitPainter(p);
+}
+
+void ECDPST::buttonStateChanged( const QString &, bool state )
+{
+ m_switch1->setState( state ? Switch::Closed : Switch::Open );
+ m_switch2->setState( state ? Switch::Closed : Switch::Open );
+ pressed = state;
+}
+//END class ECDPST
+
+
+//BEGIN class ECSPDT
+Item* ECSPDT::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECSPDT( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ECSPDT::libraryItem()
+{
+ return new LibraryItem(
+ QString("ec/spdt_toggle"),
+ i18n("SPDT"),
+ i18n("Switches"),
+ "spdt.png",
+ LibraryItem::lit_component,
+ ECSPDT::construct );
+}
+
+
+ECSPDT::ECSPDT( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, (id) ? id : "spdt_toggle" )
+{
+ m_name = i18n("SPDT Toggle");
+ m_desc = i18n("Single-Pole Double-Throw switch.");
+ setSize( -16, -16, 32, 32 );
+
+ addButton( "button", QRect( -16, 16, width(), 20 ), "", true );
+
+ createProperty( "button_text", Variant::Type::String );
+ property("button_text")->setCaption( i18n("Button Text") );
+
+ Variant * v = createProperty( "bounce", Variant::Type::Bool );
+ v->setCaption("Bounce");
+ v->setAdvanced(true);
+ v->setValue(false);
+
+ v = createProperty( "bounce_period", Variant::Type::Double );
+ v->setCaption("Bounce Period");
+ v->setAdvanced(true);
+ v->setUnit("s");
+ v->setValue(5e-3);
+
+ init1PinLeft( 0 );
+ init2PinRight( -8, 8 );
+
+ m_switch1 = createSwitch( m_pNNode[0], m_pPNode[0], false );
+ m_switch2 = createSwitch( m_pNNode[0], m_pPNode[1], true );
+
+ pressed = false;
+}
+
+
+ECSPDT::~ECSPDT()
+{
+}
+
+
+void ECSPDT::dataChanged()
+{
+ button("button")->setText( dataString("button_text") );
+
+ bool bounce = dataBool("bounce");
+ int bouncePeriod_ms = int(dataDouble("bounce_period")*1e3);
+
+ m_switch1->setBounce( bounce, bouncePeriod_ms );
+ m_switch2->setBounce( bounce, bouncePeriod_ms );
+}
+
+
+void ECSPDT::drawShape( QPainter &p )
+{
+ initPainter(p);
+
+ int _x = (int)x()-16;
+ int _y = (int)y()-16;
+ const int radius = 2;
+
+ p.drawEllipse( _x, _y+15, 2*radius, 2*radius );
+ p.drawEllipse( _x+width()-2*radius+1, _y+6, 2*radius, 2*radius );
+ p.drawEllipse( _x+width()-2*radius+1, _y+22, 2*radius, 2*radius );
+
+ const int dy = pressed ? 21 : 10;
+ p.drawLine( _x+2*radius, _y+16, _x+width()-2*radius+2, _y+dy );
+
+ deinitPainter(p);
+}
+
+void ECSPDT::buttonStateChanged( const QString &, bool state )
+{
+ pressed = state;
+ m_switch1->setState( state ? Switch::Open : Switch::Closed );
+ m_switch2->setState( state ? Switch::Closed : Switch::Open );
+}
+//END class ECSPDT
+
+
+//BEGIN class ECSPST
+Item* ECSPST::construct( ItemDocument *itemDocument, bool newItem, const char *id )
+{
+ return new ECSPST( (ICNDocument*)itemDocument, newItem, id );
+}
+
+LibraryItem* ECSPST::libraryItem()
+{
+ return new LibraryItem(
+ QString("ec/spst_toggle"),
+ i18n("SPST"),
+ i18n("Switches"),
+ "spst.png",
+ LibraryItem::lit_component,
+ ECSPST::construct
+ );
+}
+
+
+ECSPST::ECSPST( ICNDocument *icnDocument, bool newItem, const char *id )
+ : Component( icnDocument, newItem, (id) ? id : "spst_toggle" )
+{
+ m_name = i18n("SPST Toggle");
+ m_desc = i18n("Single-Pole Single-Throw switch.");
+ setSize( -16, -8, 32, 16 );
+ pressed = false;
+
+ addButton( "button", QRect( -16, 8, width(), 20 ), "", true );
+
+ createProperty( "button_text", Variant::Type::String );
+ property("button_text")->setCaption( i18n("Button Text") );
+
+ Variant * v = createProperty( "bounce", Variant::Type::Bool );
+ v->setCaption("Bounce");
+ v->setAdvanced(true);
+ v->setValue(false);
+
+ v = createProperty( "bounce_period", Variant::Type::Double );
+ v->setCaption("Bounce Period");
+ v->setAdvanced(true);
+ v->setUnit("s");
+ v->setValue(5e-3);
+
+ button("button")->setState(pressed);
+
+ init1PinLeft();
+ init1PinRight();
+
+ m_switch = createSwitch( m_pNNode[0], m_pPNode[0], !pressed );
+}
+
+
+ECSPST::~ECSPST()
+{
+}
+
+
+void ECSPST::dataChanged()
+{
+ button("button")->setText( dataString("button_text") );
+
+ bool bounce = dataBool("bounce");
+ int bouncePeriod_ms = int(dataDouble("bounce_period")*1e3);
+ m_switch->setBounce( bounce, bouncePeriod_ms );
+}
+
+
+void ECSPST::drawShape( QPainter &p )
+{
+ initPainter(p);
+
+ int _x = (int)x()-16;
+ int _y = (int)y()-8;
+ const int radius = 2;
+
+ p.drawEllipse( _x, _y+7, 2*radius, 2*radius );
+ p.drawEllipse( _x+width()-2*radius+1, _y+7, 2*radius, 2*radius );
+ const int dy = pressed ? 0 : -6;
+ p.drawLine( _x+2*radius, _y+8, _x+width()-2*radius, _y+8+dy );
+
+ deinitPainter(p);
+}
+
+void ECSPST::buttonStateChanged( const QString &, bool state )
+{
+ pressed = state;
+ m_switch->setState( state ? Switch::Closed : Switch::Open );
+}
+//END class ECSPST
+
diff --git a/src/electronics/components/toggleswitch.h b/src/electronics/components/toggleswitch.h
new file mode 100644
index 0000000..80fd064
--- /dev/null
+++ b/src/electronics/components/toggleswitch.h
@@ -0,0 +1,116 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#ifndef TOGGLESWITCH_H
+#define TOGGLESWITCH_H
+
+#include "component.h"
+
+/**
+@short Double Pole Double Throw
+@author David Saxton
+*/
+class ECDPDT : public Component
+{
+public:
+ ECDPDT( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECDPDT();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+ virtual void buttonStateChanged( const QString &id, bool state );
+ virtual void dataChanged();
+ virtual bool canFlip() const { return true; }
+
+private:
+ virtual void drawShape( QPainter &p );
+ Switch *m_switch1;
+ Switch *m_switch2;
+ Switch *m_switch3;
+ Switch *m_switch4;
+ bool pressed;
+};
+
+
+/**
+@short Double Pole Single Throw
+@author David Saxton
+*/
+class ECDPST : public Component
+{
+public:
+ ECDPST( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECDPST();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+ virtual void buttonStateChanged( const QString &id, bool state );
+ virtual void dataChanged();
+ virtual bool canFlip() const { return true; }
+
+private:
+ virtual void drawShape( QPainter &p );
+ Switch *m_switch1;
+ Switch *m_switch2;
+ bool pressed;
+};
+
+
+/**
+@short Single Pole Double Throw
+@author David Saxton
+*/
+class ECSPDT : public Component
+{
+public:
+ ECSPDT( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECSPDT();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+ virtual void buttonStateChanged( const QString &id, bool state );
+ virtual void dataChanged();
+ virtual bool canFlip() const { return true; }
+
+private:
+ virtual void drawShape( QPainter &p );
+ Switch *m_switch1;
+ Switch *m_switch2;
+ bool pressed;
+};
+
+
+/**
+@short Single-Pole Single-Throw Switch
+@author David Saxton
+*/
+class ECSPST : public Component
+{
+public:
+ ECSPST( ICNDocument *icnDocument, bool newItem, const char *id = 0L );
+ ~ECSPST();
+
+ static Item* construct( ItemDocument *itemDocument, bool newItem, const char *id );
+ static LibraryItem *libraryItem();
+
+ virtual void buttonStateChanged( const QString &id, bool state );
+ virtual void dataChanged();
+ virtual bool canFlip() const { return true; }
+
+private:
+ virtual void drawShape( QPainter &p );
+ Switch *m_switch;
+ bool pressed;
+};
+
+#endif