001 
002 /*
003  *  JScripter Standard 1.0 - To Script In Java
004  *  Copyright (C) 2008-2011  J.J.Liu<jianjunliu@126.com> <http://www.jscripter.org>
005  *  
006  *  This program is free software: you can redistribute it and/or modify
007  *  it under the terms of the GNU Affero General Public License as published by
008  *  the Free Software Foundation, either version 3 of the License, or
009  *  (at your option) any later version.
010  *  
011  *  This program is distributed in the hope that it will be useful,
012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014  *  GNU Affero General Public License for more details.
015  *  
016  *  You should have received a copy of the GNU Affero General Public License
017  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
018  */
019 
020 package jsx.ui.vect.draw;
021 
022 import js.Id;
023 import js.Js;
024 import jsx.Configurable;
025 import jsx.core.ObjectLikes;
026 import jsx.ui.Component;
027 import jsx.ui.dd.Mouse;
028 import jsx.ui.dd.event.DragMove;
029 import jsx.ui.dd.event.DragStart;
030 import jsx.ui.dd.event.DragStop;
031 import jsx.ui.dd.event.OnDragMove;
032 import jsx.ui.dd.event.OnDragStart;
033 import jsx.ui.dd.event.OnDragStop;
034 import jsx.ui.event.Position;
035 import jsx.ui.vect.Graphic;
036 
037 /**
038  * <p>An abstract base class for drawing tools that can interactively draw vector graphics.</p>
039  * <p>A vector graphics drawing tool wraps either a VML component for IE or a SVG 
040  * component for other browsers and draws a specific type of shapes in accordance with 
041  * the {@link Mouse} handle to which it listens mouse events, eliminating the browser 
042  * dependencies.</p>
043  * <p>A {@link Draw} widget is {@link Configurable} and is also an event source which 
044  * may fire high level events.</p>
045  * 
046  * @author <a href="mailto:jianjunliu@126.com">J.J.Liu (Jianjun Liu)</a> at <a href="http://www.jscripter.org" target="_blank">http://www.jscripter.org</a>
047  */
048 public abstract class Draw extends Graphic implements OnDragStart, OnDragMove, OnDragStop
049 {
050     /**
051      * <p>A global identifier for a configurable property of a {@link Draw} object.</p>
052      * <p>The identified configurable property of a {@link Draw} widget refers to 
053      * its {@link Mouse} handle to which the widget listens mouse events.</p>
054      * @since 1.0
055      */
056     protected final static Id<Mouse> MOUSE = new Id<Mouse>();
057     /**
058      * <p>A global identifier for a configurable property of a {@link Draw} object.</p>
059      * <p>The identified configurable property of a {@link Draw} widget caches the 
060      * latest mouse press event that occurs on the canvas. This property also tells 
061      * whether the vector graphic widget is in a drawing mode.</p>
062      * @since 1.0
063      */
064     protected final static Id<Position<?>> START = new Id<Position<?>>();
065     /**
066      * <p>A global identifier for a configurable property of a {@link Draw} object.</p>
067      * <p>The identified configurable property of a {@link Draw} widget caches the 
068      * X coordinate of the left-corner of its underlying graphic component.</p>
069      * @since 1.0
070      */
071     protected final static Id<Integer> X = new Id<Integer>();
072     /**
073      * <p>A global identifier for a configurable property of a {@link Draw} object.</p>
074      * <p>The identified configurable property of a {@link Draw} widget caches the 
075      * Y coordinate of the left-corner of its underlying graphic component.</p>
076      * @since 1.0
077      */
078     protected final static Id<Integer> Y = new Id<Integer>();
079 
080     /**
081      * <p>The default constructor that constructs a wrapper widget of this type.</p>
082      * <p>This constructor invokes the default constructor of the superclass to create 
083      * a default underlying graphic component.</p>
084      * @since 1.0
085      */
086     protected Draw() {}
087 
088     /**
089      * <p>Gets the mouse handle currently attached to this vector drawing wrapper.</p>
090      * <p>This method simply returns the configurable property {@link #MOUSE} of this 
091      * wrapper widget.</p>
092      * @return The mouse widget attached to this vector drawing tool.
093      * @since 1.0
094      */
095     public final Mouse getMouse() {
096         return ini(this).var(MOUSE);
097     }
098 
099     /**
100      * <p>Attaches a specified mouse handle to the vector drawing widget.</p>
101      * <p>This method detaches the old mouse handle if there is one and attaches the 
102      * specified one to the current drawing widget enabling it to listen the necessary 
103      * types of mouse events from the mouse handle. Call this method from event listeners 
104      * with caution.</p>
105      * @param h The new mouse widget to be attached to the vector drawing tool.
106      * @since 1.0
107      * @see #detach()
108      */
109     public final void attach(Mouse h) {
110         if (Js.be(getMouse())) {
111             detach();
112         }
113         ini(this).var(MOUSE, h);
114         h.addListener(DragStart.class, this);
115         h.addListener(DragMove .class, this);
116         h.addListener(DragStop .class, this);
117     }
118 
119     /**
120      * <p>Detaches the current mouse handle from the vector drawing widget.</p>
121      * <p>This method removes the mouse handle currently attached to the drawing 
122      * widget and unregisters it as an event listener from the mouse widget with all 
123      * event types. Call the method from event listeners with caution.</p>
124      * @since 1.0
125      * @see #attach(Mouse)
126      */
127     public final void detach() {
128         Mouse h = getMouse();
129         if (Js.be(h)) {
130             h.removeListener(DragStart.class, this);
131             h.removeListener(DragMove .class, this);
132             h.removeListener(DragStop .class, this);
133             ObjectLikes.delete(ini(this), MOUSE);
134         }
135     }
136 
137     /**
138      * <p>Draws a line with the two specified positions.</p>
139      * <p>This method draws a line from a position computed with the first specified 
140      * mouse {@link Position} data and the position data cached by the specified vector 
141      * drawing tool to that computed with the second argument position.</p>
142      * <p>A subclass may also call this method to meet its particular needs.</p>
143      * @param d A vector drawing wrapper.
144      * @param p1 A mouse position event.
145      * @param p2 A mouse position event.
146      * @since 1.0
147      */
148     protected static final Component line(Draw d, Position<?> p1, Position<?> p2) {
149         Component e = Graphic.line(
150                 ini(p1).var(Position.X).doubleValue() - ini(d).var(X),
151                 ini(p1).var(Position.Y).doubleValue() - ini(d).var(Y),
152                 ini(p2).var(Position.X).doubleValue() - ini(d).var(X),
153                 ini(p2).var(Position.Y).doubleValue() - ini(d).var(Y)
154         );
155         Graphic.stroke(e, "red");
156         Graphic.strokeWidth(e, "3");
157         Graphic.add(d, e);
158         return e;
159     }
160 
161     /**
162      * <p>Draws a line with the specified position.</p>
163      * <p>This method draws a line from the current position of a specified graphic 
164      * {@link Component} to a new position computed with the specified mouse 
165      * {@link Position} data and the position data cached by the specified vector 
166      * drawing tool.</p>
167      * <p>A subclass may also call this method to meet its particular needs.</p>
168      * @param d A vector drawing wrapper.
169      * @param v The graphic component wrapped by the specified vector drawing tool.
170      * @param p A mouse position event.
171      * @since 1.0
172      */
173     protected static final void lineTo(Draw d, Component v, Position<?> p) {
174         Graphic.lineTo(
175                 v,
176                 ini(p).var(Position.X).doubleValue() - ini(d).var(X),
177                 ini(p).var(Position.Y).doubleValue() - ini(d).var(Y)
178         );
179     }
180 
181     /**
182      * <p>Performs an action on the dispatched event.</p>
183      * <p>This method enters the drawing mode and initializes the vector drawing tool 
184      * and the internal caches.</p>
185      * @param evt The event dispatched to this listener.
186      * @since 1.0
187      */
188     public void onEvent(DragStart evt) {
189         if (Js.not(ini(this).var(START))) {
190             ini(this).var(START, evt);
191             Component e = unwrap();
192             ini(this).var(X, (int)e.pageLeft());
193             ini(this).var(Y, (int)e.pageTop ());
194         }
195     }
196 }