rotoswitch.cpp

00001 /***************************************************************************
00002  *   Copyright (C) 2005 by John Myers                                      *
00003  *   electronerd@electronerdia.net                                         *
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU General Public License as published by  *
00007  *   the Free Software Foundation; either version 2 of the License, or     *
00008  *   (at your option) any later version.                                   *
00009  ***************************************************************************/
00010 
00011 #include "rotoswitch.h"
00012 
00013 #include "canvasitemparts.h"
00014 #include "ecnode.h"
00015 #include "libraryitem.h"
00016 #include "switch.h"
00017 
00018 #include <klocale.h>
00019 #include <qpainter.h>
00020 #include <cmath>
00021 #include <cassert>
00022 
00023 #include <kdebug.h>
00024 
00025 //BEGIN class ECRotoSwitch
00026 Item* ECRotoSwitch::construct( ItemDocument *itemDocument, bool newItem, const char *id )
00027 {
00028     return new ECRotoSwitch( (ICNDocument*)itemDocument, newItem, id );
00029 }
00030 
00031 LibraryItem* ECRotoSwitch::libraryItem()
00032 {
00033     return new LibraryItem(
00034                             QString("ec/roto_switch"),
00035                             i18n("Rotary"),
00036                             i18n("Switches"),
00037                             "rotary.png",
00038                             LibraryItem::lit_component,
00039                             ECRotoSwitch::construct );
00040 }
00041 
00042 
00043 ECRotoSwitch::ECRotoSwitch( ICNDocument *icnDocument, bool newItem, const char *id )
00044 : Component( icnDocument, newItem, id ? id : "roto_switch" ),
00045 m_numPositions(0)
00046 {
00047 //      m_name = i18n("Rotary Switch(WIP)");
00048         m_name = i18n("Rotary Switch");
00049     m_desc = i18n("A single-throw N-position switch");
00050     QPointArray pa;
00051     pa.makeArc( -_pinInnerRadius, -_pinInnerRadius, 2*_pinInnerRadius, 2*_pinInnerRadius , 0, 16*360 );
00052     setItemPoints( pa );
00053     //setSize( -64, -64, 128, 128 );
00054     
00055     //half the side length of the buttons
00056     int buttonRadius = 10;
00057     addButton( "go_left", QRect( -_pinOuterRadius/3-buttonRadius, _pinOuterRadius-3*buttonRadius, 2*buttonRadius, 2*buttonRadius ), "<", false );
00058     addButton( "go_right", QRect(_pinOuterRadius/3-buttonRadius, _pinOuterRadius-3*buttonRadius, 2*buttonRadius, 2*buttonRadius ), ">", false );
00059     
00060     /*Variant * v = createProperty( "button_map", Variant::Type::String );
00061     v->setCaption( i18n("Button Map") );
00062     v->setAdvanced(true);
00063     const QString defButtonMap("SSSSSSSSSSSM");
00064     v->setValue(defButtonMap);
00065     */
00066     Variant * v = createProperty( "num_positions", Variant::Type::Int );
00067     v->setCaption( i18n("Number of Positions") );
00068     v->setAdvanced(false);
00069     v->setValue(6);
00070     v->setMinValue(3);
00071     m_inNode = createPin(0,height()/2,270,"in");    
00072 
00073     v = createProperty( "bounce", Variant::Type::Bool );
00074     v->setCaption("Bounce");
00075     v->setAdvanced(true);
00076     v->setValue(false);
00077 
00078     v = createProperty( "bounce_period", Variant::Type::Double );
00079     v->setCaption("Bounce Period");
00080     v->setAdvanced(true);
00081     v->setUnit("s");
00082     v->setValue(5e-3);
00083 
00084     v = createProperty( "cur_position", Variant::Type::Int );
00085     v->setHidden( true );
00086     v->setValue( 0 );
00087 
00088     //v = createProperty( "left_momentary", Variant::Type::Bool );
00089     //v->setCaption(i18n("Left Momentary" ) );
00090     //v->setValue(false);
00091 }
00092 
00093 
00094 ECRotoSwitch::~ECRotoSwitch()
00095 {
00096 }
00097 
00098 
00099 void ECRotoSwitch::dataChanged()
00100 {
00101     bool bounce = dataBool("bounce");
00102     int bouncePeriod_ms = int(dataDouble("bounce_period")*1e3);
00103     m_curPosition = dataInt( "cur_position" );
00104     setUpSwitches();
00105     if(m_positions[m_curPosition].posSwitch->state() != Switch::Closed)
00106     {
00107         m_positions[m_curPosition].posSwitch->setState(Switch::Closed);
00108     }
00109     for(int i = 0; i < m_numPositions; i++)
00110     {
00111         m_positions[i].posSwitch->setBounce( bounce, bouncePeriod_ms );
00112     }
00113 }
00114 
00115 inline int roundTo10(int a){return ((a/10)+(a%10<5?0:1))*10;}
00116 void ECRotoSwitch::drawShape( QPainter &p )
00117 {
00118     initPainter(p);
00119 
00120     int cx = static_cast<int>(x());
00121     int cy =  static_cast<int>(y());
00122 
00123     const int rotorRadius = 5;
00124 
00125     //draw the rotor
00126     p.drawEllipse(cx - rotorRadius, cy-rotorRadius, 2*rotorRadius, 2*rotorRadius);
00127     //and its connection
00128     p.drawLine(cx, cy+rotorRadius, cx, cy+_pinInnerRadius);
00129 
00130     //draw the output positions
00131     double angleBetweenPositions = (4*M_PI/3)/(m_numPositions - 1);
00132     //kdDebug() << "drawShape: " << bigRadius << " " << angleBetweenPositions << endl;
00133 
00135 #define round_8(a)      (((a) > 0) ? int(((a)+4)/8)*8 : int(((a)-4)/8)*8)
00136     for(int i = 0; i < m_numPositions ; i++)
00137     {
00138         double angle = (7*M_PI/6) - (i * angleBetweenPositions);
00139         int contactX = static_cast<int>(_contactRingRadius * cos(angle));
00140         int contactY = static_cast<int>(_contactRingRadius * sin(angle));
00141 
00142         p.drawEllipse(cx+contactX-_contactRadius, cy-contactY-_contactRadius, 2*_contactRadius, 2*_contactRadius);
00143         int pinX, pinY;
00144         switch(m_positions[i].pinAngle)
00145         {
00146         case 180:
00147             pinX = _pinInnerRadius;
00148             pinY = round_8(contactY);
00149             break;
00150         case 90:
00151             pinX = round_8(contactX);
00152             pinY = _pinInnerRadius;
00153             break;
00154         case 0:
00155             pinX = -_pinInnerRadius;
00156             pinY = round_8(contactY);
00157             break;
00158         default:
00159             assert(!"Bad pin angle");
00160         }
00161         p.drawLine(cx+contactX, cy-contactY, cx+pinX, cy-pinY);
00162         //kdDebug() << contactX <<", "<< contactY <<endl;
00163     }
00164 #undef round_8
00165     //draw the connection to the selected position
00166     double angle = (7*M_PI/6) - (m_curPosition * angleBetweenPositions);
00167     int contactX = static_cast<int>(_contactRingRadius * cos(angle));
00168     int contactY = static_cast<int>(_contactRingRadius * sin(angle));
00169     int rotorX = static_cast<int>(rotorRadius * cos(angle));
00170     int rotorY = static_cast<int>(rotorRadius * sin(angle));
00171     p.drawLine(cx+rotorX, cy-rotorY, cx+contactX, cy-contactY);
00172 
00173     deinitPainter(p);
00174 }
00175 
00176 void ECRotoSwitch::buttonStateChanged( const QString & id, bool state )
00177 {
00178     SwitchPosition& curSP = m_positions[m_curPosition];
00179     int nextPos = m_curPosition;
00180     if(m_numPositions < 2)
00181     {
00182         return;
00183     }
00184     if(!state) //release
00185     {
00186         if(!curSP.isMomentary)
00187         {
00188             return;
00189         }
00190 
00191         if(m_curPosition == 0)
00192         {
00193             nextPos = m_curPosition + 1;
00194         }
00195         else if(m_curPosition == m_numPositions - 1)
00196         {
00197             nextPos = m_curPosition - 1;
00198         }
00199 
00200     }
00201     else //press
00202     {
00203         if(id == "go_left" && m_curPosition > 0)
00204         {
00205             nextPos = m_curPosition - 1;
00206         }
00207         else if(id == "go_right" && m_curPosition < m_numPositions - 1)
00208         {
00209             nextPos = m_curPosition + 1;
00210         }
00211 
00212     }
00213     if(nextPos != m_curPosition)
00214     {
00215         SwitchPosition& nextSP = m_positions[nextPos];
00216 
00217         curSP.posSwitch->setState(Switch::Open);
00218         nextSP.posSwitch->setState(Switch::Closed);
00219 
00220         m_curPosition = nextPos;
00221 
00222         property( "cur_position" )->setValue( m_curPosition );
00223     }
00224 }
00225 
00226 
00232 void ECRotoSwitch::setUpSwitches()
00233 {
00234     if( dataInt("num_positions") == m_numPositions )
00235     {
00236         // number of positions didn't change, so we don't have to do anything.
00237         return;
00238     }
00239     //this uses the _old_ value of m_numPositions!
00240     for(int i=0; i<m_numPositions; i++)
00241     {
00242         SwitchPosition& sp = m_positions[i];
00243         QString pinName = QString("pin_%1").arg(i);
00244         removeNode(pinName);
00245         removeSwitch(sp.posSwitch);
00246     }
00247 
00248     m_numPositions = dataInt("num_positions");
00249     if(m_curPosition >= m_numPositions )
00250     {
00251         setActivePosition( m_numPositions - 1 );
00252     }
00253     m_positions.clear();
00254     m_positions.reserve(m_numPositions);
00255     double angleBetweenPositions = (4*M_PI/3)/(m_numPositions - 1);
00256     //kdDebug() << "setUpSwitches: " << bigRadius << " " << angleBetweenPositions << endl;
00257     for( int i = 0; i < m_numPositions; i++)
00258     {
00259         double angle = (7*M_PI/6) - (i * angleBetweenPositions);
00260         int contactX = static_cast<int>(_contactRingRadius * cos(angle));
00261         int contactY = static_cast<int>(_contactRingRadius * sin(angle));
00262 
00263         SwitchPosition sp;
00264         if(angle > 3*M_PI/4)
00265         {
00266             sp.pinAngle = 0;
00267             contactX = -_pinOuterRadius;
00268         }
00269         else if(angle > M_PI/4)
00270         {
00271             sp.pinAngle = 90;
00272             contactY=_pinOuterRadius;
00273         }
00274         else 
00275         {
00276             sp.pinAngle = 180;
00277             contactX = _pinOuterRadius;
00278         }
00279         // kdDebug() << contactX <<", "<< contactY <<endl;
00280         
00281         
00282         sp.node = createPin(contactX,-contactY,sp.pinAngle,QString("pin_%1").arg(i));
00283         sp.posSwitch = createSwitch(m_inNode, sp.node, true);
00284         sp.isMomentary = false;//(map[i] == 'M');
00285         m_positions.push_back(sp);
00286     }
00287     updateAttachedPositioning();
00288 
00289         // redraw ourself
00290         setChanged();
00291 }
00292 
00299 void ECRotoSwitch::setActivePosition(int newPosition)
00300 {
00301     SwitchPosition& curSP = m_positions[m_curPosition];
00302     SwitchPosition& nextSP = m_positions[newPosition];
00303 
00304     curSP.posSwitch->setState(Switch::Open);
00305     nextSP.posSwitch->setState(Switch::Closed);
00306 
00307     m_curPosition = newPosition;
00308 
00309     property( "cur_position" )->setValue( m_curPosition );
00310 
00311 }
00312 //END class ECRotoSwitch

Generated on Tue May 8 17:05:32 2007 for KTechLab by  doxygen 1.5.1