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.canvas;
021 
022 import js.Id;
023 import js.Initializer;
024 import js.Js;
025 import js.ObjectLike;
026 import jsx.Configurable;
027 import jsx.core.ObjectLikes;
028 import jsx.dom.Styles;
029 import jsx.ui.Component;
030 import jsx.ui.dd.Mouse;
031 import jsx.ui.dd.event.DragMove;
032 import jsx.ui.dd.event.DragStart;
033 import jsx.ui.dd.event.DragStop;
034 import jsx.ui.vect.Canvas;
035 
036 /**
037  * <p>An abstract base class for drawing tools that can interactively draw on a wrapped 
038  * canvas with the help of a cached draft canvas.</p>
039  * <p>A drawing tool of a subclass of this one wraps a {@link Canvas} component and 
040  * draws a specific type of shapes in accordance with the {@link Mouse} handle to which 
041  * it listens mouse events but shows the intermediate drawings on a draft canvas.</p>
042  * <p>A {@link CanvasDraft} widget is {@link Configurable} and is also an event source 
043  * which may fire high level events.</p>
044  * 
045  * @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>
046  */
047 public abstract class CanvasDraft extends CanvasDraw
048 {
049     /**
050      * <p>A global identifier for a configurable property of a {@link CanvasDraft} object.</p>
051      * <p>The identified configurable property of a {@link CanvasDraft} widget caches the 
052      * latest mouse press event that occurs on the canvas.</p>
053      * @since 1.0
054      */
055     protected final static Id<DragStart> PRESS = new Id<DragStart>();
056     /**
057      * <p>A global identifier for a configurable property of a {@link CanvasDraft} object.</p>
058      * <p>The identified configurable property of a {@link CanvasDraft} widget caches the 
059      * draft canvas widget cached by the canvas drawing tool.</p>
060      * @since 1.0
061      */
062     protected final static Id<Canvas> DRAFT = new Id<Canvas>();
063 
064     /**
065      * <p>A typical constructor that constructs a wrapper widget of this type and forces 
066      * constructors of subclasses to pass a {@link Canvas} widget.</p>
067      * <p>This constructor invokes the typical constructor of the superclass passing 
068      * the component wrapped by the specified {@link Canvas} widget that is set to the 
069      * configurable property {@link CanvasDraw#CANVAS} of the widget to be constructed.</p>
070      * @param c A canvas widget.
071      * @since 1.0
072      */
073     protected CanvasDraft(Canvas c) {
074         super(c);
075     }
076 
077     /**
078      * <p>Gets the draft canvas cached by this canvas drawing wrapper.</p>
079      * <p>This method simply returns the configurable property {@link #DRAFT} of this 
080      * wrapper widget if it exists. If it does not, this method will create a new one, 
081      * set it to the property and return it.</p>
082      * @return The draft canvas cached by this canvas drawing tool.
083      * @since 1.0
084      */
085     protected static final Canvas getDraft(CanvasDraw d) {
086         Canvas t = ini(d).var(DRAFT);
087         if (Js.not(t)) {
088             t = Canvas.create();
089             ini(d).var(DRAFT, t);
090             Canvas c = d.canvas();
091             Canvas.width (t, Canvas.width (c));
092             Canvas.height(t, Canvas.height(c));
093             Canvas.fillStyle  (t, Canvas.fillStyle  (c));
094             Canvas.strokeStyle(t, Canvas.strokeStyle(c));
095             Canvas.lineWidth  (t, Canvas.lineWidth  (c));
096             ObjectLike o = new Initializer().var();
097             Styles.left(o, Styles.px(ini(d).var(X)));
098             Styles.top (o, Styles.px(ini(d).var(Y)));
099             Styles.position(o, "absolute");
100             Styles.zIndex(o, "9999");
101             Component.applyStyle(t.unwrap(), o);
102         }
103         return t;
104     }
105 
106     /**
107      * <p>Performs an action on the dispatched event.</p>
108      * <p>This method invokes the overridden method of the superclass to initialize and caches the 
109      * mouse press event in the configurable property {@link #PRESS} of the current canvas 
110      * drawing tool.</p>
111      * @param evt The event dispatched to this listener.
112      * @since 1.0
113      */
114     @Override
115     public void onEvent(DragStart evt) {
116         super.onEvent(evt);
117         ini(this).var(PRESS, evt);
118     }
119 
120     /**
121      * <p>Performs an action on the dispatched event.</p>
122      * <p>This method clears the cached draft canvas if the current canvas drawing tool 
123      * is in a drawing mode.</p>
124      * @param evt The event dispatched to this listener.
125      * @since 1.0
126      */
127     public void onEvent(DragMove evt) {
128         if (Js.be(ini(this).var(START))) {
129             Canvas t = getDraft(this);
130             Canvas.clearRect(t, 0, 0, Canvas.width(t), Canvas.height(t));
131         }
132     }
133 
134     /**
135      * <p>Performs an action on the dispatched event.</p>
136      * <p>If the current canvas drawing tool is in a drawing mode this method deletes 
137      * the cached draft canvas.</p>
138      * @param evt The event dispatched to this listener.
139      * @since 1.0
140      */
141     public void onEvent(DragStop evt) {
142         if (Js.be(ini(this).var(START))) {
143             Canvas t = ini(this).var(DRAFT);
144             if (Js.be(t)) {
145                 Component e = t.unwrap();
146                 ObjectLikes.delete(ini(this), DRAFT);
147                 Component.detach(e);
148             }
149         }
150     }
151 }