diff options
Diffstat (limited to 'src/electronics/components/rotoswitch.cpp')
-rw-r--r-- | src/electronics/components/rotoswitch.cpp | 317 |
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 |