001package votorola.s.gwt.stage.vote; // 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.event.logical.shared.ResizeEvent; 004import com.google.gwt.event.logical.shared.ResizeHandler; 005import com.google.gwt.user.client.Window; 006import com.google.gwt.user.client.ui.*; 007import com.google.web.bindery.event.shared.HandlerRegistration; 008import votorola.g.hold.*; 009import votorola.g.web.gwt.*; 010import votorola.g.web.gwt.event.*; 011 012 013/** A device to calculate the dimensions and drawing parameters of node views. This is 014 * complicated because the rendered size of the SVG element is unknown, its offset 015 * dimensions always being reported as zero (at least with Firefox 9). As a workaround, 016 * the calculations are based instead on the rendered size of the HTML container. For 017 * this to work correctly, it is crucial that the sizes of the two match. SVG overflow 018 * <a href='https://bugzilla.mozilla.org/show_bug.cgi?id=378923' target='_top'>cannot be 019 * made visible</a> in Firefox; so if the SVG element happens to be smaller than the 020 * container, then its overflow will end up being truncated ("hidden"). Ideally the 021 * element should be set to 100% of the container size in <a 022 * href='../../../../../../../a/web/context/stage/vote/track.css' >vote/track.css</a>. 023 */ 024abstract class NodeVPainter implements PropertyChangeHandler, ResizeHandler 025{ 026 027 028 /** Partially creates a NodeVPainter for {@linkplain #init(Spool) init} to 029 * finish. 030 * 031 * @see #container() 032 */ 033 NodeVPainter( MajorV _container ) { container = _container; } 034 035 036 037 /** Completes the creation of this NodeVPainter and activates it. Call once 038 * only, preferably after the {@linkplain #container() HTML container} is rendered. 039 * 040 * @param _spool the spool for the release of associated holds. When unwound it 041 * releases the holds of the painter and thereby disables it. 042 */ 043 final void init( Spool _spool ) 044 { 045 spool = _spool; 046 GWTX.i().bus().addHandlerToSource( PropertyChange.TYPE, /*source*/container, 047 NodeVPainter.this ); // no need to unregister, registry does not outlive the handler 048 // svg.addResizeHandler( NodeVPainter.this ); 049 /// no effect, as size of OMSVGSVGElement is stable, apparently related to logical size of drawing 050 spool.add( new Hold() 051 { 052 final HandlerRegistration hR = Window.addResizeHandler( NodeVPainter.this ); 053 public void release() { hR.removeHandler(); } 054 }); 055 } 056 057 058 059 // ------------------------------------------------------------------------------------ 060 061 062 /** The HTML container whose rendered size determines the dimensions of the node 063 * views. 064 */ 065 final UIObject container() { return container; } 066 067 068 private final UIObject container; 069 070 071 072 /** The margin to respect below the node view in pixels. 073 */ 074 static final int MARGIN_BOTTOM = 3/*apparent*/ - NodeV.STROKE_WIDTH / 2; 075 076 077 078 /** The margin to respect above the node view in pixels. 079 */ 080 static final int MARGIN_TOP = 2/*apparent*/ - NodeV.STROKE_WIDTH / 2; 081 082 083 084 /** Forces a recalibration. 085 */ 086 final void repaint() { repaint( container.getOffsetWidth() ); } 087 088 089 090 /** Effects a recalibration and redraws the node views accordingly. 091 * 092 * @param width the rendered width of the {@linkplain #container() HTML 093 * container}. 094 * @see NodeV#repaint(float,float,float,int,float) 095 */ 096 abstract void repaint( int width, float protrusion, int y, float halfThickness ); 097 098 099 100 // - P r o p e r t y - C h a n g e - H a n d l e r ------------------------------------ 101 102 103 public void onPropertyChange( final PropertyChange e ) 104 { 105 if( spool.isUnwinding() ) return; 106 107 if( e.getSource() == container && e.propertyName().equals("visible") 108 && container.isVisible() ) // becomes visible 109 { 110 if( widthCalibrated == -1 ) repaint(); // width changed meantime, so repaint 111 } 112 } 113 114 115 116 // - R e s i z e - H a n d l e r -------------------------------------------------- 117 118 119 public final void onResize( ResizeEvent _e ) 120 { 121 if( spool.isUnwinding() ) return; 122 123 final int width = container.getOffsetWidth(); 124 if( width == widthCalibrated ) return; 125 126 repaint( width ); 127 } 128 129 130 131//// P r i v a t e /////////////////////////////////////////////////////////////////////// 132 133 134 private void repaint( final int width ) 135 { 136 if( !container.isVisible() ) 137 { 138 widthCalibrated = -1; // skipping calibration, therefore no width is calibrated 139 return; 140 } 141 142 widthCalibrated = width; 143 final int height = container.getOffsetHeight(); 144 final float halfThickness = (height - MARGIN_TOP - MARGIN_BOTTOM) / 2f; 145 final float protrusion = halfThickness; 146 repaint( width, protrusion, /*y*/MARGIN_TOP, halfThickness ); 147 } 148 149 150 151 private Spool spool; // final after init 152 153 154 155 private int widthCalibrated = -1; /* guard against redundant resize events, assumes 156 that window resize cannot affect container height, only width */ 157 158 159}