package votorola.s.gwt.scene.vote; // Copyright 2011, 2013, Michael Allan. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Votorola Software"), to deal in the Votorola Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicence, and/or sell copies of the Votorola Software, and to permit persons to whom the Votorola Software is furnished to do so, subject to the following conditions: The preceding copyright notice and this permission notice shall be included in all copies or substantial portions of the Votorola Software. THE VOTOROLA SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE VOTOROLA SOFTWARE OR THE USE OR OTHER DEALINGS IN THE VOTOROLA SOFTWARE. import com.google.gwt.dom.client.Style; import org.vectomatic.dom.svg.*; import votorola.a.count.gwt.*; import votorola.g.lang.*; import static org.vectomatic.dom.svg.OMSVGLength.SVG_LENGTHTYPE_PX; import static votorola.s.gwt.scene.vote.VoterCircle.VOTER_CIRCLE_RADIUS; /** A view of a voter's count node. */ final class VoterNodeV extends NodeV { /** Constructs a VoterNodeV. * * @param parent the parent circle to be {@linkplain * #setParent(votorola.g.web.gwt.svg.SVGNest) set} by the caller. It must * never be changed. * * @see #dartSector() */ VoterNodeV( final VotespaceV vV, final int dartSector, final Circle parent ) { super( vV, dartSector ); // initParent = parent; // LAYOUT rightward of candidate // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = final float pxPerEm = vV.pxPerEm(); // Mnemonic. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { final OMSVGTextElement text = vV.document().createSVGTextElement(); localView().appendChild( text ); text.addClassNameBaseVal( "mnemonic" ); vV.append( text.getY(), 0.35f ); // down, center in nodular standoff text.appendChild( mnemonicTextNode() ); } // Voteflow radial back (left) to candidate // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - final float radialOuterMargin = parent.nodularStandOff() - 0.4f; // outer somewhat tighter { final OMSVGLineElement line = vV.document().createSVGLineElement(); svgView().appendChild( line ); line.addClassNameBaseVal( "voteflow" ); line.getX1().getBaseVal().setValue( -radialOuterMargin * pxPerEm ); final float x2 = -VOTER_CIRCLE_RADIUS + parent.inCircle().nodularStandOff(); line.getX2().getBaseVal().setValue( x2 * pxPerEm ); } // Carry cast count. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - final float outflowMargin = radialOuterMargin + 1.1f; outflowVSur = newCarryCastV( vV, -outflowMargin ); outflowVSur.addClassNameBaseVal( "sur" ); outflowVSub = newCarryCastV( vV, outflowMargin ); outflowVSub.addClassNameBaseVal( "sub" ); outflowVSub.setAttribute( "transform", "rotate(180)" ); // TRANSFORM angularly and radially // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = svgView().setAttribute( "transform", "rotate(" + angleToNode( dartSector ) + ") translate(" + VOTER_CIRCLE_RADIUS * pxPerEm + ")" ); } // ------------------------------------------------------------------------------------ /** Calculates the angle of the voter node at the specified dart sector. * * @see votorola.a.count.CountNode#dartSector() */ static float angleToNode( final int dartSector ) { return (dartSector - 10.5f) * INTER_VOTER_ANGLE; // aligns 10 and 11 to angle zero } /** The angle between voter nodes within the circle. */ static final float INTER_VOTER_ANGLE = 11.6f; // - C o u n t - N o d e - V ---------------------------------------------------------- @Override void repaintRegister( final CountingMethodJS.SwitchMnemonic mCM, final String accountName ) { final CountNodeJS node = model(); if( node == null ) return; final long outflowVolume; if( mCM == CountingMethodJS.SwitchMnemonic.q ) { final SacRegisterJS_q r = node.register( mCM.fullName(), accountName ); if( r == null ) outflowVolume = 0; // no such superaccount else outflowVolume = r.castVolume() + r.carryVolume(); } else if( mCM == CountingMethodJS.SwitchMnemonic.v ) { final SacRegisterJS_v r = node.register( mCM.fullName(), accountName ); if( r == null ) outflowVolume = 0; // no such superaccount else outflowVolume = r.castVolume() + r.carryVolume(); } else throw new IllegalArgumentException(); final OMSVGMatrix currentTransforms = svgView().getCTM(); final FlowVolumeV outflowVOn; final FlowVolumeV outflowVOff; if( currentTransforms.getA() > 0 ) // on right side, -90 < angle <= 90 { outflowVOn = outflowVSur; outflowVOff = outflowVSub; } else // on left side, 90 < angle <= 270 { outflowVOn = outflowVSub; outflowVOff = outflowVSur; } outflowVOff.getStyle().setDisplay( Style.Display.NONE ); if( outflowVolume > 0 ) // superaccount exists and outflow is non-zero { outflowVOn.set( outflowVolume ); outflowVOn.getStyle().clearDisplay(); } else outflowVOn.getStyle().setDisplay( Style.Display.NONE ); } @Override boolean setModel( final CountNodeJS node ) { if( !super.setModel( node )) return false; if( node != null ) { localView().getElement().setPropertyString( "votepath", DartScoping.DIGIT_ENCODER.charAt(node.dartSector()) + parent().candidateV().votepath() ); final SacRegisterJS_v r = node.voteRegister(); final long outflowVolume = r.castVolume() + r.carryVolume(); setMosquito( outflowVolume < parent().mosquitoBar() ); } return true; } // - S V G - P a r a - N e s t ------------------------------------------------------ // private final Circle initParent; // // // public final @Override @Warning("init call") void setParent( final Circle circle ) // { // assert initParent.equals( circle ): "parent not changed after construction"; // super.setParent( circle ); // } // /// Stack overflow (!) between here and super method in devmode, and apparently super /// method not called at all when compiled (GWT 2.1.1). Do without this guard for now. //// P r i v a t e /////////////////////////////////////////////////////////////////////// private final FlowVolumeV outflowVSur; private final FlowVolumeV outflowVSub; private FlowVolumeV newCarryCastV( final VotespaceV vV, final float x ) { final FlowVolumeV outflowV = new FlowVolumeV( vV ); svgView().appendChild( outflowV ); outflowV.addClassNameBaseVal( "radial" ); vV.append( outflowV.getX(), x ); vV.append( outflowV.getY(), -0.3f ); // up from radial line return outflowV; } }