/*************************************************************************** * 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 #include #include #include #include //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( TQString("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 TQPointArray 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", TQRect( -_pinOuterRadius/3-buttonRadius, _pinOuterRadius-3*buttonRadius, 2*buttonRadius, 2*buttonRadius ), "<", false ); addButton( "go_right", TQRect(_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 TQString 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( TQPainter &p ) { initPainter(p); int cx = static_cast(x()); int cy = static_cast(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(_contactRingRadius * cos(angle)); int contactY = static_cast(_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 <(_contactRingRadius * cos(angle)); int contactY = static_cast(_contactRingRadius * sin(angle)); int rotorX = static_cast(rotorRadius * cos(angle)); int rotorY = static_cast(rotorRadius * sin(angle)); p.drawLine(cx+rotorX, cy-rotorY, cx+contactX, cy-contactY); deinitPainter(p); } void ECRotoSwitch::buttonStateChanged( const TQString & 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 ) { 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(_contactRingRadius * cos(angle)); int contactY = static_cast(_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 <setState(Switch::Open); nextSP.posSwitch->setState(Switch::Closed); m_curPosition = newPosition; property( "cur_position" )->setValue( m_curPosition ); } //END class ECRotoSwitch