PageRenderTime 37ms CodeModel.GetById 14ms app.highlight 19ms RepoModel.GetById 1ms app.codeStats 1ms

/src/org/mt4j/components/css/util/CSSHelper.java

http://mt4j.googlecode.com/
Java | 415 lines | 256 code | 67 blank | 92 comment | 42 complexity | 79b568c8dadfc876b380ba21d4a1a111 MD5 | raw file
  1package org.mt4j.components.css.util;
  2
  3import java.util.ArrayList;
  4import java.util.Collections;
  5import java.util.List;
  6
  7import org.mt4j.MTApplication;
  8import org.mt4j.components.MTComponent;
  9import org.mt4j.components.StateChange;
 10import org.mt4j.components.StateChangeEvent;
 11import org.mt4j.components.StateChangeListener;
 12import org.mt4j.components.TransformSpace;
 13import org.mt4j.components.clipping.Clip;
 14import org.mt4j.components.css.style.CSSStyle;
 15import org.mt4j.components.css.style.CSSStyle.BackgroundRepeat;
 16import org.mt4j.components.css.style.CSSStyleHierarchy;
 17import org.mt4j.components.css.util.CSSKeywords.Position;
 18import org.mt4j.components.visibleComponents.shapes.MTCSSStylableShape;
 19import org.mt4j.components.visibleComponents.shapes.MTPolygon;
 20import org.mt4j.components.visibleComponents.widgets.MTImage;
 21import org.mt4j.util.MT4jSettings;
 22import org.mt4j.util.MTColor;
 23import org.mt4j.util.math.Tools3D;
 24import org.mt4j.util.math.Vector3D;
 25import org.mt4j.util.math.Vertex;
 26import org.mt4j.util.opengl.GLTexture;
 27import org.mt4j.util.opengl.GLTexture.EXPANSION_FILTER;
 28import org.mt4j.util.opengl.GLTexture.SHRINKAGE_FILTER;
 29import org.mt4j.util.opengl.GLTexture.TEXTURE_TARGET;
 30import org.mt4j.util.opengl.GLTexture.WRAP_MODE;
 31import org.mt4j.util.opengl.GLTextureSettings;
 32
 33import processing.core.PImage;
 34
 35/**
 36 * The Class CSSHelper.
 37 */
 38public class CSSHelper {
 39
 40	/** The private style sheets (unique to an object) */
 41	private List<CSSStyle> privateStyleSheets = new ArrayList<CSSStyle>();
 42
 43	/** The currently relevant global style sheet */
 44	private List<CSSStyleHierarchy> sheets = new ArrayList<CSSStyleHierarchy>();
 45	
 46	/** The virtual style sheet (generated from the global and private style sheets) */
 47	private CSSStyle virtualStyleSheet = null;
 48	
 49	/** The CSS style manager. */
 50	private CSSStyleManager cssStyleManager;
 51	
 52	/** The MTApplication. */
 53	private MTApplication app;
 54	
 55	/** The MTComponent. */
 56	private MTComponent c;
 57
 58	/**
 59	 * Instantiates a new CSS helper.
 60	 *
 61	 * @param c the MTComponent
 62	 * @param a the MTApplication
 63	 */
 64	public CSSHelper(MTComponent c, MTApplication a) {
 65		this.c = c;
 66		this.app = a;
 67		this.cssStyleManager = a.getCssStyleManager();
 68		addListeners();
 69	}
 70
 71	/**
 72	 * Instantiates a new CSS helper.
 73	 *
 74	 * @param c the MTComponent
 75	 * @param a the MTApplication
 76	 * @param s the new private CSSStyle
 77	 */
 78	public CSSHelper(MTComponent c, MTApplication a, CSSStyle s) {
 79		this(c,a);
 80		this.getPrivateStyleSheets().add(s);
 81		
 82
 83	}
 84
 85	/**
 86	 * Instantiates a new CSS helper.
 87	 *
 88	 * @param c the MTComponent
 89	 * @param a the MTApplication
 90	 * @param s the list of private style sheets
 91	 */
 92	public CSSHelper(MTComponent c, MTApplication a, List<CSSStyle> s) {
 93		this(c,a);
 94		this.getPrivateStyleSheets().addAll(s);
 95	}
 96
 97	/**
 98	 * Adds the listeners to the MTComponent, so applyStyleSheet() is called every time the component is added as child
 99	 */
100	private void addListeners() {
101		if (c instanceof MTCSSStylableShape) {
102			final MTCSSStylableShape cssShape = (MTCSSStylableShape) c;
103			cssShape.addStateChangeListener(StateChange.ADDED_TO_PARENT,
104					new StateChangeListener() {
105						public void stateChanged(StateChangeEvent evt) {
106							cssShape.applyStyleSheet();//rather leave the applyStyleSheet() method and implementation to the component itself
107//							applyStyleSheet(CSSHelper.this.c);
108						}
109					});
110			
111		}
112	}
113
114	/**
115	 * Apply the style sheet. Disambiguate between different subclasses of MTComponent
116	 */
117	public void applyStyleSheet(MTComponent c) {
118		//This method can be used by a component which  only implements the cssstylable interface and 
119		//doesent extend MTCssStylableShape to get some standard behaviour
120		//like the calling of applyStyleSheet on all their children
121		if (c instanceof CSSStylableComponent) {
122			CSSStylableComponent sc = (CSSStylableComponent)c;
123			if (!sc.isCssForceDisabled() && ((sc.isCSSStyled() && !app.getCssStyleManager().isGloballyDisabled()) || app.getCssStyleManager().isGloballyEnabled())) {
124				evaluateStyleSheets();
125				
126				for (MTComponent d : c.getChildren()) {
127					if (d instanceof CSSStylableComponent) {
128						CSSStylableComponent s = (CSSStylableComponent) d;
129						s.applyStyleSheet();
130					}
131				}
132			}
133		}
134	}
135
136
137	/**
138	 * Evaluate the style sheets (in order of relevance).
139	 */
140	private void evaluateStyleSheets() {
141		sheets = cssStyleManager.getRelevantStyles(c);
142		Collections.sort(sheets);
143		virtualStyleSheet = new CSSStyle(app);
144		for (CSSStyleHierarchy h : sheets) {
145			virtualStyleSheet.addStyleSheet(h.getStyle());
146
147		}
148		for (CSSStyle s : privateStyleSheets) {
149			virtualStyleSheet.addStyleSheet(s);
150		}
151
152	}
153
154	/**
155	 * Gets the private style sheets.
156	 *
157	 * @return the private style sheets
158	 */
159	public List<CSSStyle> getPrivateStyleSheets() {
160		return privateStyleSheets;
161	}
162
163	/**
164	 * Gets the currently relevant style sheets.
165	 *
166	 * @return the sheets
167	 */
168	public List<CSSStyleHierarchy> getSheets() {
169		return sheets;
170	}
171
172	/**
173	 * Gets the x distance (between a float and a Vertex)
174	 *
175	 * @param x the x-position
176	 * @param v2 the vertex to compare to
177	 * @return the x-distance
178	 */
179	private static float getXDistance(float x, Vertex v2) {
180		float distance = v2.x - x;
181		if (distance >= 0)
182			return distance;
183		else
184			return -distance;
185
186	}
187
188	/**
189	 * Gets the y distance (between a float and a vertex)
190	 *
191	 * @param y the y-position
192	 * @param v2 the vertex to compare to
193	 * @return the y-distance
194	 */
195	private static  float getYDistance(float y, Vertex v2) {
196		float distance = v2.y - y;
197		if (distance >= 0)
198			return distance;
199		else
200			return -distance;
201	}
202
203	/**
204	 * Sets the private style sheets.
205	 *
206	 * @param privateStyleSheets the new private style sheets
207	 */
208	public void setPrivateStyleSheets(List<CSSStyle> privateStyleSheets) {
209		this.privateStyleSheets = privateStyleSheets;
210	}
211
212	/**
213	 * Sets the relevant style sheets.
214	 *
215	 * @param sheets the new sheets
216	 */
217	public void setSheets(List<CSSStyleHierarchy> sheets) {
218		this.sheets = sheets;
219	}
220
221	/**
222	 * Adds a style sheet.
223	 *
224	 * @param sheet the new style sheet
225	 */
226	public void setStyleSheet(CSSStyle sheet) {
227		this.privateStyleSheets.add(sheet);
228	}
229
230	/**
231	 * Sets the texture for a tiled background.
232	 *
233	 * @param p the MTPolygon to apply it to
234	 * @param bgImage the background-image
235	 */
236	public void setBackground(MTPolygon p) {
237		PImage bgImage = virtualStyleSheet.getBackgroundImage();
238		if (bgImage != null) {
239		if (virtualStyleSheet.getBackgroundRepeat() != BackgroundRepeat.NONE) {
240			
241		boolean pot = Tools3D.isPowerOfTwoDimension(bgImage);
242		boolean tiled = true;
243		p.setFillColor(MTColor.WHITE);
244		if (tiled) {
245			// Generate texture coordinates to repeat the texture over the whole
246			// background (works only with OpenGL)
247
248
249			Vertex[] backgroundVertices = p.getVerticesLocal();
250
251			float minx, miny;
252
253			if (backgroundVertices.length > 0) {
254				minx = backgroundVertices[0].x;
255				miny = backgroundVertices[0].y;
256
257				for (Vertex vtx : backgroundVertices) {
258					if (vtx.x < minx)
259						minx = vtx.x;
260					if (vtx.y < miny)
261						miny = vtx.y;
262				}
263
264				for (Vertex vtx : backgroundVertices) {
265					vtx.setTexCoordU(getXDistance(minx, vtx)
266							/ bgImage.width);
267					vtx.setTexCoordV(getYDistance(miny, vtx)
268							/ bgImage.height);
269				}
270
271			}
272
273			// Update changed texture coordinates for opengl buffer drawing
274			if (MT4jSettings.getInstance().isOpenGlMode())
275				p.getGeometryInfo().updateTextureBuffer(p.isUseVBOs());
276		}
277		
278		WRAP_MODE horizontal = WRAP_MODE.CLAMP, vertical = WRAP_MODE.CLAMP;
279		switch (virtualStyleSheet.getBackgroundRepeat()) {
280		case REPEAT:
281			horizontal = WRAP_MODE.REPEAT;
282			vertical = WRAP_MODE.REPEAT;
283		case XREPEAT:
284			horizontal = WRAP_MODE.REPEAT;
285		case YREPEAT:
286			vertical = WRAP_MODE.REPEAT;
287		}
288				
289		
290		if (MT4jSettings.getInstance().isOpenGlMode()) {
291
292			GLTextureSettings g = new GLTextureSettings(
293					TEXTURE_TARGET.TEXTURE_2D,
294					SHRINKAGE_FILTER.BilinearNoMipMaps,
295					EXPANSION_FILTER.Bilinear, horizontal,
296					vertical);
297			GLTexture tex;
298			if (pot) {
299				tex = new GLTexture(app, bgImage, g);
300			} else {
301				if (tiled) {
302					g.target = TEXTURE_TARGET.RECTANGULAR;
303					g.shrinkFilter = SHRINKAGE_FILTER.Trilinear; // Because NPOT texture with GL_REPEAT isnt supported
304																	// -> gluBuild2Dmipmapds strechtes the texture to POT size
305
306					tex = new GLTexture(app, bgImage, g);
307				} else {
308					g.target = TEXTURE_TARGET.RECTANGULAR;
309
310					tex = new GLTexture(app, bgImage, g);
311				}
312			}
313			p.setTexture(tex);
314		} else {
315			p.setTexture(bgImage);
316		}
317		} else {
318			if (virtualStyleSheet.getBackgroundPosition() != null) {
319			MTImage img = new MTImage(app,bgImage);
320			p.addChild(img);
321			img.setPickable(false);
322			
323			
324			float xPos = 0;
325			float yPos = 0;
326			
327			switch (virtualStyleSheet.getBackgroundPosition().getxType()) {
328			case ABSOLUTE:
329				xPos = virtualStyleSheet.getBackgroundPosition().getxPos();
330				break;
331			case RELATIVE:
332				xPos = determineAbsolutePosition(p, virtualStyleSheet.getBackgroundPosition().getxPos(), true);
333				break;
334			case KEYWORD:
335				xPos = determineAbsolutePosition(p, virtualStyleSheet.getBackgroundPosition().getxKeywordPosition(), true);
336				break;
337			}
338			
339			switch (virtualStyleSheet.getBackgroundPosition().getyType()) {
340			case ABSOLUTE:
341				xPos = virtualStyleSheet.getBackgroundPosition().getyPos();
342				break;
343			case RELATIVE:
344				xPos = determineAbsolutePosition(p, virtualStyleSheet.getBackgroundPosition().getyPos(), false);
345				break;
346			case KEYWORD:
347				xPos = determineAbsolutePosition(p, virtualStyleSheet.getBackgroundPosition().getyKeywordPosition(), false);
348				break;
349			}
350			
351				img.setPositionRelativeToParent(
352						p.getVerticesLocal()[0].addLocal(calcPos(p, virtualStyleSheet.getBackgroundImage(), xPos, yPos)));
353			
354				
355			Clip c = new Clip(app, p.getBounds().getVectorsLocal()[0].x,p.getBounds().getVectorsLocal()[0].y,p.getBounds().getWidthXY(TransformSpace.LOCAL),p.getBounds().getHeightXY(TransformSpace.LOCAL));	
356				
357			img.setClip(c);	
358			//p.setChildClip(new Clip(p));
359			
360			
361		}	else {
362			p.setTexture(bgImage);
363		} 
364			
365		}
366		}
367	}
368	
369	private float determineAbsolutePosition(MTPolygon p, Position po, boolean isHorizontal) {
370		float returnValue = 0;
371		if (isHorizontal) {
372			switch (po) {
373			case LEFT:
374				return calcPos(p,virtualStyleSheet.getBackgroundImage(), 0,0).x;
375			case RIGHT:
376				return calcPos(p,virtualStyleSheet.getBackgroundImage(), p.getWidthXY(TransformSpace.LOCAL) - (float)virtualStyleSheet.getBackgroundImage().width,0).x;
377			case CENTER:
378				return calcPos(p,virtualStyleSheet.getBackgroundImage(), (p.getWidthXY(TransformSpace.LOCAL) / 2f) - ((float)virtualStyleSheet.getBackgroundImage().width/2f),0).x;
379			}
380		} else {
381			switch (po) {
382			case TOP:
383				return calcPos(p,virtualStyleSheet.getBackgroundImage(), 0,0).y;
384			case BOTTOM:
385				return calcPos(p, virtualStyleSheet.getBackgroundImage(), 0, p.getHeightXY(TransformSpace.LOCAL) - (float)virtualStyleSheet.getBackgroundImage().height).y;
386			case CENTER:
387				return calcPos(p, virtualStyleSheet.getBackgroundImage(), 0, (p.getHeightXY(TransformSpace.LOCAL)/2f) - ((float)virtualStyleSheet.getBackgroundImage().height / 2f)).y;
388			}
389		}
390		
391		
392		return returnValue;
393	}
394	private float determineAbsolutePosition(MTPolygon p, float po, boolean isHorizontal) {
395		
396		if (isHorizontal) {
397			return calcPos(p, virtualStyleSheet.getBackgroundImage(), p.getWidthXY(TransformSpace.LOCAL) * po ,0).x;
398		} else {
399			return calcPos(p, virtualStyleSheet.getBackgroundImage(), 0 ,p.getHeightXY(TransformSpace.LOCAL) * po).x;
400		}
401		
402	}
403	private Vector3D calcPos(MTPolygon box, PImage ta, float xo, float yo) {
404
405		return new Vector3D((ta.width / 2)	+ xo, 
406				(ta.height / 2) + yo);
407	}
408
409	public CSSStyle getVirtualStyleSheet() {
410		evaluateStyleSheets();
411		return virtualStyleSheet;
412	}
413	
414	
415}