001package votorola.s.gwt.stage.poll; // 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.core.client.GWT;
004import com.google.gwt.dom.client.*;
005import com.google.gwt.event.dom.client.*;
006import com.google.gwt.uibinder.client.*;
007import com.google.gwt.user.client.ui.*;
008import votorola.g.hold.*;
009import votorola.g.lang.*;
010import votorola.s.gwt.stage.*;
011import votorola.s.gwt.stage.light.*;
012
013import static com.google.gwt.dom.client.Style.Unit.PX;
014
015
016/** A projection just above the mouse cursor showing the name of the cued poll.
017  */
018final class HeadsUpDisplay extends Composite
019  implements Actuator<PollV.Sensor>, Light<PollV.Sensor>
020{
021
022
023    /** Creates a HeadsUpDisplay.  Create at most one for the entire life of the trackV
024      * registry, as currently it does not unregister its listeners there.
025      *
026      *     @param spool the spool for the release of associated holds.  When unwound it
027      *       releases the holds of this display and thereby disables it.
028      */
029    HeadsUpDisplay( final PolltrackV trackV, final Spool spool )
030    {
031        Stage.i().lightBank().addLight( HeadsUpDisplay.this );
032        spool.add( new Hold()
033        {
034            public void release() { Stage.i().lightBank().removeLight( HeadsUpDisplay.this ); }
035        });
036        new Shuttler( trackV );
037        redisplay();
038    }
039
040
041
042   // ` e a r l y ````````````````````````````````````````````````````````````````````````
043
044
045    @Warning("non-API") interface UiBinderI extends UiBinder<HTMLPanel,HeadsUpDisplay> {}
046
047        {
048            final UiBinderI uiBinder = GWT.create( UiBinderI.class );
049            initWidget( uiBinder.createAndBindUi( HeadsUpDisplay.this ));
050        }
051
052
053
054   // - A c t u a t o r ------------------------------------------------------------------
055
056
057    public void changed( final PollV.Sensor sensor )
058    {
059        if( sensor == litSensor ) redisplay();
060    }
061
062
063
064    public Light<PollV.Sensor> light() { return HeadsUpDisplay.this; }
065
066
067
068    public void out( final PollV.Sensor sensor )
069    {
070        if( sensor != litSensor ) return; // already out
071
072        litSensor = null;
073        redisplay();
074    }
075
076
077
078    public void over( final PollV.Sensor sensor )
079    {
080        if( sensor == litSensor ) return; // already over
081
082        litSensor = sensor;
083        redisplay();
084    }
085
086
087
088   // - C o m p o s i t e ----------------------------------------------------------------
089
090
091    protected @Override HTMLPanel getWidget() { return (HTMLPanel)super.getWidget(); }
092
093
094
095   // - L i g h t ------------------------------------------------------------------------
096
097
098    public Actuator<PollV.Sensor> assignActuator( final PollV.Sensor sensor )
099    {
100        return HeadsUpDisplay.this;
101    }
102
103
104
105    public final PollV.Sensor tryCast( final Sensor sensor )
106    {
107        return sensor instanceof PollV.Sensor? (PollV.Sensor)sensor: null;
108    }
109
110
111
112//// P r i v a t e ///////////////////////////////////////////////////////////////////////
113
114
115    /** The fixed width of the expander element that contains the left field.  It is large
116      * enough for almost any poll name.  Fixing it enables the shuttle to be positioned
117      * such that the boundary between the left and right fields is directly above the
118      * cued poll.
119      */
120    private static final int EXPANDER_WIDTH_PX = 150; // same as span.expander width in track.css
121
122
123
124    @UiField @Warning("non-API") SpanElement leftField;
125
126
127
128    private final Text leftText = Document.get().createTextNode( "" );
129
130        { leftField.appendChild( leftText ); }
131
132
133
134    private PollV.Sensor litSensor;
135
136
137
138    private @Warning("init call") void redisplay()
139    {
140        if( litSensor == null ) shuttle.getStyle().setOpacity( 0 ); // hide it
141        else
142        {
143            final PollV litView = litSensor.view();
144            leftText.setData( litView.pollNameLeft() );
145            rightText.setData( litView.pollNameRight() );
146            shuttle.getStyle().clearOpacity(); // to default, opaque and thus visible
147        }
148    }
149
150
151
152    @UiField @Warning("non-API") SpanElement rightField;
153
154
155
156    private final Text rightText = Document.get().createTextNode( "" );
157
158        { rightField.appendChild( rightText ); }
159
160
161
162    @UiField @Warning("non-API") DivElement shuttle;
163
164
165
166   // ====================================================================================
167
168
169    /** A controller to position this display.
170      */
171    private final class Shuttler implements MouseMoveHandler, MouseOverHandler
172    {
173
174        Shuttler( final PolltrackV trackV )
175        {
176            trackV.addDomHandler( Shuttler.this, MouseMoveEvent.getType() ); // no need to unregister, registry does not outlive the handler
177            trackV.addDomHandler( Shuttler.this, MouseOverEvent.getType() ); // "
178        }
179
180
181        private void reposition( final MouseEvent<?> e )
182        {
183            final int left = e.getX() - EXPANDER_WIDTH_PX - /*aesthetic adjust*/4;
184            /// need rendered width of field to position properly
185            final int visibleOffset = leftField.getClientWidth()- EXPANDER_WIDTH_PX + 2;
186            if( left < visibleOffset ) shuttle.getStyle().setLeft( visibleOffset, PX );
187            else shuttle.getStyle().setLeft( left , PX );
188        }
189
190
191       // - M o u s e - M o v e - H a n d l e r ------------------------------------------
192
193
194        public void onMouseMove( final MouseMoveEvent e ) { reposition( e ); }
195
196
197       // - M o u s e - O v e r - H a n d l e r ------------------------------------------
198
199
200        public void onMouseOver( final MouseOverEvent e ) { reposition( e ); }
201
202    }
203
204
205}