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.dd;
021 
022 import js.ArrayLike;
023 import js.Id;
024 import js.Js;
025 import js.Vars;
026 import jsx.core.Variables;
027 import jsx.ui.Component;
028 import jsx.ui.Widget;
029 
030 /**
031  * <p>A class for widgets of resizer to handle resizing operations of mouse.</p>
032  * <p>A resizer is a mouse handle that can be added to a component with a call to method 
033  * {@link Resizer#addResizers(Component, int)} to resize it in a specified direction.</p>
034  * 
035  * @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>
036  */
037 public class Resizer extends Mouse
038 {
039     private final static Id<ArrayLike<Resizer>> RESIZERS = new Id<ArrayLike<Resizer>>();
040 
041     /**
042      * <p>Gets an array of all the resizers added to a specified component.</p>
043      * @param e A component.
044      * @since 1.0
045      */
046     public static final ArrayLike<Resizer> getAll(Component e) {
047         ArrayLike<Resizer> resizers = ini(e).var(RESIZERS);
048         if (Js.not(resizers)) {
049             resizers = new Vars<Resizer>().var();
050             ini(e).var(RESIZERS, resizers);
051         }
052         return resizers;
053     }
054 
055     private final static Id<Integer> MASK = new Id<Integer>();
056 
057     /**
058      * <p>This constant is a legal value for the second argument of the method {@link #addResizers(Component, int)} 
059      * meaning to create resizers in all eight directions.</p>
060      * @since 1.0
061      * @see #mask(int)
062      * @see #addResizers(Component, int)
063      */
064     public final static int ALL = 255;
065 
066     /**
067      * <p>Converts a resizer direction number to a bit mask number.</p>
068      * @param dir A number telling which direction a resizer resizes. Possible values 
069      * for this argument are:
070      * <ul>
071      * <li>{@link Resizable#N}: Only the north border is allowed to move for resizing.</li>
072      * <li>{@link Resizable#S}: Only the south border is allowed to move for resizing.</li>
073      * <li>{@link Resizable#E}: Only the east border is allowed to move for resizing.</li>
074      * <li>{@link Resizable#W}: Only the west border is allowed to move for resizing.</li>
075      * <li>{@link Resizable#SE}: Only the south-east corner is allowed to move for resizing.</li>
076      * <li>{@link Resizable#SW}: Only the south-west corner is allowed to move for resizing.</li>
077      * <li>{@link Resizable#NE}: Only the north-east corner is allowed to move for resizing.</li>
078      * <li>{@link Resizable#NW}: Only the north-west corner is allowed to move for resizing.</li>
079      * </ul>
080      * @return A integer number with only the <tt>dir</tt>th bit set.
081      * @since 1.0
082      * @see #addResizers(Component, int)
083      */
084     public static final int mask(int dir) {
085         return 1 << dir;
086     }
087 
088     /**
089      * <p>Adds required resizers to a specified component.</p>
090      * @param e A component that needs resizers.
091      * @param bits An integer with each set bit adding a resizer to the component.
092      * <ul>
093      * <li>The 1st bit means a resizer in the direction of {@link Resizable#N}.</li>
094      * <li>The 2nd bit means a resizer in the direction of {@link Resizable#S}.</li>
095      * <li>The 3rd bit means a resizer in the direction of {@link Resizable#E}.</li>
096      * <li>The 4th bit means a resizer in the direction of {@link Resizable#W}.</li>
097      * <li>The 5th bit means a resizer in the direction of {@link Resizable#SE}.</li>
098      * <li>The 6th bit means a resizer in the direction of {@link Resizable#SW}.</li>
099      * <li>The 7th bit means a resizer in the direction of {@link Resizable#NE}.</li>
100      * <li>The 8th bit means a resizer in the direction of {@link Resizable#NW}.</li>
101      * </ul>
102      * @since 1.0
103      * @see #mask(int)
104      * @see #getResizer(Component, int)
105      */
106     public static final void addResizers(Component e, int bits) {
107         int resizers = mask(e);
108         ini(e).var(MASK, resizers | bits);
109         bits ^= resizers;
110         for (int dir = Resizable.N; Js.be(bits); dir++, bits >>= 1) {
111             if (Js.be(bits & 1)) {
112                 Resizable r = new Resizable(e, dir);
113                 ini(r).var(Resizable.DELEGABLE, true);
114                 r.attach(getResizer(e, dir));
115             }
116         }
117     }
118 
119     public static final void addResizers(Widget w, int bits) {
120         addResizers(w.unwrap(), bits);
121         Component.addClasses(w.unwrap(), w.subs("resizable"));
122         
123     }
124 
125     private static final int mask(Component e) {
126         Integer resizers = ini(e).var(MASK);
127         return Variables.undefined(resizers) ? 0 : resizers;
128     }
129 
130     /**
131      * <p>A typical constructor forcing constructors of subclasses to pass a component.</p>
132      * <p>This constructor simply invokes the constructor with the same type of argument 
133      * as this one passing the specified component.</p>
134      * @param e The underlying component.
135      * @since 1.0
136      */
137     protected Resizer(Component e) {
138         super(e);
139     }
140 
141     private final static ArrayLike<String> DIRS = new Vars<String>()
142         .add("n" ).add("s" ).add("e" ).add("w" )
143         .add("se").add("sw").add("ne").add("nw").var();
144 
145     /**
146      * <p>Gets a resizer for a component in a specified direction.</p>
147      * @param e A component to get a resizer.
148      * @param dir The direction to get the resizer in.Possible values for this argument 
149      * are:
150      * <ul>
151      * <li>{@link Resizable#N}: Gets the resizer of the north border of the component.</li>
152      * <li>{@link Resizable#S}: Gets the resizer of the north border of the component.</li>
153      * <li>{@link Resizable#E}: Gets the resizer of the north border of the component.</li>
154      * <li>{@link Resizable#W}: Gets the resizer of the north border of the component.</li>
155      * <li>{@link Resizable#SE}: Gets the resizer of the south-east corner of the component.</li>
156      * <li>{@link Resizable#SW}: Gets the resizer of the south-west corner of the component.</li>
157      * <li>{@link Resizable#NE}: Gets the resizer of the north-east corner of the component.</li>
158      * <li>{@link Resizable#NW}: Gets the resizer of the north-west corner of the component.</li>
159      * </ul>
160      * @return A resizer of the component in the specified direction. If the component 
161      * does not have a resizer in that direction, this method will creates one and 
162      * returns it.
163      * @since 1.0
164      * @see #addResizers(Component, int)
165      */
166     public static final Resizer getResizer(Component e, int dir) {
167         ArrayLike<Resizer> all = getAll(e);
168         Resizer r = all.get(dir);
169         if (Js.not(r)) {
170             Component.addClass(e, css(Resizable.class));
171             Component me = Component.div();
172             Component.appendChild(e, me);
173             r = new Resizer(me);
174             Component.addClass(r.unwrap(), css(r.getClass(), "handle"));
175             Component.addClass(r.unwrap(), css(r.getClass(), DIRS.get(dir)));
176             all.set(dir, r);
177         }
178         return r;
179     }
180 }