summaryrefslogtreecommitdiffstats
path: root/src/electronics/components/rotoswitch.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/electronics/components/rotoswitch.cpp')
-rw-r--r--src/electronics/components/rotoswitch.cpp317
1 files changed, 317 insertions, 0 deletions
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