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}