001package votorola.s.gwt.wic; // Copyright 2012-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.
002
003import com.google.gwt.dom.client.*;
004import org.vectomatic.dom.svg.*;
005import votorola.g.web.gwt.*;
006import votorola.g.web.gwt.event.*;
007import votorola.g.web.gwt.svg.*;
008import votorola.s.gwt.stage.vote.*;
009
010
011/** A component of the bridge/stage {@linkplain DIn connector overlay} that shows the
012  * position in the vote track of the other (non-anchor) drafter of the difference
013  * pair.<pre>
014  *
015  *    - - ---+-----+---+----------+---+----------------+---+
016  *            \     \   \          \   \                \   \
017  *             +     +   +          +   +                +   +  vote track
018  *            /     /   /          /   /                /   /
019  *    - - ---+-----+---+----------+---+----------------+---+
020  *
021  *                                 p0 +                  +   -
022  *                                    |                  |   | depth
023  *                                    +------------------+   -
024  *
025  *                                    |----- length -----|</pre>
026  */
027final class AlterBracket extends OMSVGPathElement
028{
029
030    // A simple underline would be preferable if the eye could easily resolve it.  But it
031    // gets lost in the extreme contrast at the bottom edge of the stage.
032
033
034    /** Partially creates an AlterBracket, which an initial call to {@linkplain #repaint()
035      * repaint} will finish.  Create at most one for the entire life of the document as
036      * currently it does not unregister its listeners or otherwise clean up after itself.
037      */
038    AlterBracket( final NodeV.Box nodeBox, NodeV _nodeV, AlterLine _alterLine )
039    {
040        nodeV = _nodeV;
041        alterLine = _alterLine;
042
043        addClassNameBaseVal( "AlterBracket" );
044        final OMSVGPathSegList sL = getPathSegList();
045   /*0*/sL.appendItem( createSVGPathSegMovetoAbs( 0,0 ));
046   /*1*/sL.appendItem( createSVGPathSegLinetoRel( 0,0 ));
047   /*2*/sL.appendItem( createSVGPathSegLinetoRel( 0,0 ));
048   /*3*/sL.appendItem( createSVGPathSegLinetoRel( 0,0 ));
049        new Painter( nodeBox );
050    }
051
052
053
054    private static AlterBracket instance;
055
056        {
057            if( instance != null ) throw new IllegalStateException();
058
059            instance = AlterBracket.this;
060        }
061
062
063
064   // ------------------------------------------------------------------------------------
065
066
067    private final Element bridgeTopE = NodeX.nextElement(
068      Document.get().getElementById("stageTopHolder"), /*name, any*/null, /*deeply*/false );
069      // element marking top edge of overall bridge content, just below stage
070
071
072
073    /** The vertical depth of the drawing as currently drawn in the SVG viewport.
074      */
075    float depth()
076    {
077        final OMSVGPathSegLinetoRel seg = (OMSVGPathSegLinetoRel)getPathSegList().getItem( 1 );
078        return seg.getY();
079    }
080
081
082
083    /** The horizontal length of the drawing as currently drawn in the SVG viewport.
084      */
085    float length()
086    {
087        final OMSVGPathSegLinetoRel seg = (OMSVGPathSegLinetoRel)getPathSegList().getItem( 2 );
088        return seg.getX();
089    }
090
091
092
093    /** The point at the top left of the drawing as currently drawn in the SVG viewport.
094      */
095    OMSVGPathSegMovetoAbs p0()
096    {
097        return (OMSVGPathSegMovetoAbs)getPathSegList().getItem( 0 );
098    }
099
100
101
102    /** Redraws this bracket and calls AlterLine.{@linkplain
103      * AlterLine#repaint(AlterBracket) repaint}, or does nothing if the parent tie is
104      * invisible.
105      */
106    void repaint()
107    {
108        if( !getParentNode().isVisible() ) return;
109
110        final OMSVGPathSegList sL = getPathSegList();
111        final float protrusion = nodeV.protrusion();
112        final int protrudedLength = (int)( nodeV.length() + protrusion ); // rounds zeroward
113
114          //                                                   protrusion
115          //                                                     /
116          //                                  |---- length ----|-|        |
117          //                                                              |
118          //  - - ---+-----+---+----------+---+----------------+---+      |
119          //          \     \   \          \   \                \   \     |
120          //           +     +   +          +   +     nodeV      +   +    | stageTopHolder
121          //          /     /   /          /   /                /   /     |
122          //  - - ---+-----+---+----------+---+----------------+---+     --
123          //                      gap |                                   |
124          //                          -     0 +                  + 3      | bridgeTopE
125          //                    depth |       |                  |        |
126          //                          -     1 +------------------+ 2      |
127
128        final int gap = (int)Math.ceil( protrusion / 2 );
129        PathSeg.movetoAbs( sL, 0,
130          /*x*/nodeV.getViewportElement().getElement().getParentElement().getAbsoluteLeft()
131            + nodeV.p0().getX(), /* measure from parent (div) of viewport (svg) to avoid
132              SVG_STROKE_BUF distortion owing to path.ArrowSegment stroke */
133          /*y*/bridgeTopE.getAbsoluteTop() + gap );
134        final int depth = (int)protrusion;
135        PathSeg.lineToRel( sL, 1, /*x*/0, /*y*/depth );
136        PathSeg.lineToRel( sL, 2, /*x*/protrudedLength, /*y*/0 );
137        PathSeg.lineToRel( sL, 3, /*x*/0, /*y*/-depth );
138        alterLine.repaint( AlterBracket.this );
139    }
140
141
142
143   // - O  M - N o d e -------------------------------------------------------------------
144
145
146    public @Override AlterTie getParentNode() { return (AlterTie)super.getParentNode(); }
147
148
149
150//// P r i v a t e ///////////////////////////////////////////////////////////////////////
151
152
153    private final AlterLine alterLine;
154
155
156
157    private final NodeV nodeV;
158
159
160
161   // ====================================================================================
162
163
164    private final class Painter implements ChangeHandler
165    {
166
167        Painter( final NodeV.Box nodeBox )
168        {
169            GWTX.i().bus().addHandlerToSource( Change.TYPE, /*source*/nodeBox.painter(),
170              Painter.this ); // no need to unregister, registry does not outlive this listener
171        }
172
173
174        public final void onChange( Change _e ) { repaint(); }
175
176    }
177
178
179}