View Javadoc

1   /**********************************************
2    * Copyright (C) 2011 Lukas Laag
3    * This file is part of svgreal.
4    * 
5    * svgreal is free software: you can redistribute it and/or modify
6    * it under the terms of the GNU General Public License as published by
7    * the Free Software Foundation, either version 3 of the License, or
8    * (at your option) any later version.
9    * 
10   * svgreal is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU General Public License for more details.
14   * 
15   * You should have received a copy of the GNU General Public License
16   * along with svgreal.  If not, see http://www.gnu.org/licenses/
17   **********************************************/
18  package org.vectomatic.svg.edit.client.utils;
19  
20  import java.util.HashMap;
21  import java.util.Map;
22  
23  import com.google.gwt.canvas.client.Canvas;
24  import com.google.gwt.canvas.dom.client.Context2d;
25  import com.google.gwt.dom.client.ImageElement;
26  import com.google.gwt.resources.client.ImageResource;
27  import com.google.gwt.user.client.ui.AbstractImagePrototype;
28  
29  /**
30   * Class to create and cache images decorated by
31   * other images (typically, an image representing an object
32   * decorated by a image representing this object's status,
33   * à la eclipse)
34   * @author laaglu
35   */
36  public class DecoratedImageCache {
37  	/**
38  	 * Horizontal alignment of the decoration image
39  	 */
40  	public enum HAlign {
41  		LEFT,
42  		CENTER,
43  		RIGHT
44  	};
45  	/**
46  	 * Vertical alignment of the decoration image
47  	 */
48  	public enum VAlign {
49  		TOP,
50  		CENTER,
51  		BOTTOM
52  	};
53  	/**
54  	 * Composite key class for entries in the cache
55  	 */
56  	protected class StoreKey {
57  		private HAlign halign;
58  		private VAlign valign;
59  		private ImageResource decoration;
60  		public StoreKey(ImageResource decoration, HAlign halign, VAlign valign) {
61  			this.decoration = decoration;
62  			this.halign = halign;
63  			this.valign = valign;
64  		}
65  		@Override
66  		public String toString() {
67  			StringBuilder builder = new StringBuilder();
68  			builder.append("{");
69  			if (decoration != null) {
70  				builder.append(decoration.getName());
71  			} else {
72  				builder.append(decoration);
73  			}
74  			builder.append("; ");
75  			builder.append(halign);
76  			builder.append("; ");
77  			builder.append(valign);
78  			builder.append("}");
79  			return builder.toString();
80  		}
81  		@Override
82  		public boolean equals(Object o) {
83  			if (o instanceof StoreKey) {
84  				StoreKey storeKey = (StoreKey)o;
85  				return halign == storeKey.halign
86  				&& valign == storeKey.valign
87  				&& decoration == storeKey.decoration;
88  			}
89  			return false;
90  		}
91  		@Override
92  		public int hashCode() {
93  			return halign.hashCode() + 13 * valign.hashCode() + 37 * (decoration == null ? 0 : decoration.hashCode());
94  		}
95  	}
96  	
97  	/**
98  	 * A canvas to create the decorated images
99  	 */
100 	protected Canvas canvas;
101 	/**
102 	 * The canvas context
103 	 */
104 	protected Context2d ctx;
105 	/**
106 	 * Maps image resources to simple images
107 	 */
108 	protected Map<ImageResource, SimpleImage> resourceToImage;
109 	/**
110 	 * Cache storage
111 	 */
112 	protected Map<ImageResource,Map<StoreKey, AbstractImagePrototype>> imageToDecorations;
113 	/**
114 	 * Constructor
115 	 * @param resourceToImage
116 	 * A map containing the base images and the decoration images
117 	 */
118 	public DecoratedImageCache(Map<ImageResource, SimpleImage> resourceToImage) {
119 		this.resourceToImage = resourceToImage;
120 		imageToDecorations = new HashMap<ImageResource, Map<StoreKey, AbstractImagePrototype>>();
121 		canvas = Canvas.createIfSupported();
122 		ctx = canvas.getContext2d();
123 	}
124 	
125 	/**
126 	 * Creates or returns a decorated image
127 	 * @param base
128 	 * The base image
129 	 * @param decoration
130 	 * The image decoration
131 	 * @param halign
132 	 * Horizontal alignment of the decoration
133 	 * @param valign
134 	 * Vertical alignment of the decoration
135 	 * @return
136 	 * The decorated image
137 	 */
138 	public AbstractImagePrototype getImageWithDecoration(ImageResource base, ImageResource decoration, HAlign halign, VAlign valign) {
139 		Map<StoreKey, AbstractImagePrototype> decorationToImage = imageToDecorations.get(base);
140 		if (decorationToImage == null) {
141 			decorationToImage = new HashMap<StoreKey, AbstractImagePrototype>();
142 			imageToDecorations.put(base, decorationToImage);
143 		}
144 		StoreKey key = new StoreKey(decoration, halign, valign);
145 		AbstractImagePrototype image = decorationToImage.get(key);
146 		if (image == null) {
147 			if (decoration != null) {
148 				SimpleImage baseImg = resourceToImage.get(base);
149 				if (baseImg == null) {
150 					throw new IllegalArgumentException();
151 				}
152 				SimpleImage decorationImg = resourceToImage.get(decoration);
153 				if (decorationImg == null) {
154 					throw new IllegalArgumentException();
155 				}
156 				image = decorate(baseImg, decorationImg, halign, valign);
157 			} else {
158 				image = AbstractImagePrototype.create(base);
159 			}
160 			decorationToImage.put(key, image);
161 		}
162 		return image;
163 	}
164 	
165 	/**
166 	 * Decorates the specified image
167 	 * @param base
168 	 * The base image
169 	 * @param decoration
170 	 * The image decoration
171 	 * @param halign
172 	 * Horizontal alignment of the decoration
173 	 * @param valign
174 	 * Vertical alignment of the decoration
175 	 * @return
176 	 * The decorated image
177 	 */
178 	public AbstractImagePrototype decorate(SimpleImage base, SimpleImage decoration, HAlign halign, VAlign valign) {
179 		ctx.clearRect(0, 0, canvas.getCoordinateSpaceWidth(), canvas.getCoordinateSpaceHeight());  
180 		int baseWidth = base.getWidth();
181 		int baseHeight = base.getHeight();
182 		int decWidth = decoration.getWidth();
183 		int decHeight = decoration.getHeight();
184 		canvas.setCoordinateSpaceWidth(baseWidth);
185 		canvas.setCoordinateSpaceHeight(baseHeight);
186 		int x = 0;
187 		switch(halign) {
188 			case LEFT:
189 				break;
190 			case CENTER:
191 				x = (baseWidth - decWidth) / 2;
192 				break;
193 			case RIGHT:
194 				x = baseWidth - decWidth;
195 				break;
196 		}
197 		int y = 0;
198 		switch(valign) {
199 			case TOP:
200 				break;
201 			case CENTER:
202 				y = (baseHeight - decHeight) / 2;
203 				break;
204 			case BOTTOM:
205 				y = baseHeight - decHeight;
206 				break;
207 		}
208 		ctx.drawImage(base.getElement().<ImageElement>cast(), 0, 0);
209 		ctx.drawImage(decoration.getElement().<ImageElement>cast(), x, y);
210 		return new SimpleImagePrototype(canvas.toDataUrl(), baseWidth, baseHeight);
211 	}
212 }