package test.style { import com.yworks.canvas.ICanvasContext; import com.yworks.canvas.drawing.GeneralPath; import com.yworks.canvas.drawing.IBoundsProvider; import com.yworks.canvas.drawing.IDisplayObjectContext; import com.yworks.canvas.drawing.IHitTestable; import com.yworks.canvas.drawing.IMarqueeTestable; import com.yworks.canvas.drawing.IPaintContext; import com.yworks.canvas.drawing.YDisplayObject; import com.yworks.canvas.drawing.YGraphics; import com.yworks.canvas.geom.GeomSupport; import com.yworks.canvas.geom.IMutableRectangle; import com.yworks.canvas.geom.IPointSetter; import com.yworks.canvas.geom.IRectangle; import com.yworks.canvas.geom.YPoint; import com.yworks.canvas.geom.YRectangle; import com.yworks.graph.drawing.AbstractNodeStyleRenderer; import com.yworks.graph.drawing.ComponentNodeStyle; import com.yworks.graph.drawing.INodeStyle; import com.yworks.graph.drawing.INodeStyleRenderer; import com.yworks.graph.drawing.IShapeGeometry; import com.yworks.graph.model.INode; import com.yworks.support.ArrayList; import com.yworks.support.Iterator; import flash.display.DisplayObject; /** * This NodeStyleRenderer can be used to combine several other NodeStyles to create a new style. */ public class CompositeNodeStyleRenderer extends AbstractNodeStyleRenderer { /* IMPORTANT: this file contains code for yFiles FLEX 1.7 and higher as well as for yFiles FLEX 1.6.x and lower Developers who use yFiles FLEX 1.7 and higher may use this file as is Developers who use a lower yFiles FLEX version should - comment out the code in between the "yFiles FLEX 1.7 and higher" comments and - uncomment the code in between the "yFiles FLEX 1.6.x and lower" comments */ // BEGIN: yFiles FLEX 1.7 and higher override public function createDisplayObject(context:IDisplayObjectContext):DisplayObject { var comNS:CompositeNodeStyle = this.style as CompositeNodeStyle; var base:YDisplayObject = new YDisplayObject(); if (comNS != null) { var styleIt:Iterator = comNS.styles.iterator(); while (styleIt.hasNext()) { var style:INodeStyle = styleIt.next() as INodeStyle; var dObj:DisplayObject = style.styleRenderer.getDisplayObjectCreator(item, style).createDisplayObject(context); base.addChild(dObj); } } return base; } override public function updateDisplayObject(oldDisplayObject:DisplayObject, context:IDisplayObjectContext):DisplayObject { return createDisplayObject(context); } // END: yFiles FLEX 1.7 and higher // BEGIN: yFiles FLEX 1.6.x and lower // /** // * @inheritDoc // */ // override public function paint(g:YGraphics, ctx:IPaintContext):void { // var comNS:CompositeNodeStyle = this.style as CompositeNodeStyle; // if (comNS != null) { // var styleIt:Iterator = comNS.styles.iterator(); // while (styleIt.hasNext()) { // var style:INodeStyle = styleIt.next() as INodeStyle; // style.styleRenderer.getPaintable(item, style).paint(g, ctx); // } // } // } // END yFiles FLEX 1.6.x and lower /** * @inheritDoc */ override public function calculateBounds( scratch:IMutableRectangle, ctx:ICanvasContext ):IRectangle { var xMin:Number = Number.POSITIVE_INFINITY; var xMax:Number = Number.NEGATIVE_INFINITY; var yMin:Number = Number.POSITIVE_INFINITY; var yMax:Number = Number.NEGATIVE_INFINITY; var comNS:CompositeNodeStyle = this.style as CompositeNodeStyle; if (comNS != null) { var styleIt:Iterator = comNS.styles.iterator(); while (styleIt.hasNext()) { var subStyle:INodeStyle = styleIt.next() as INodeStyle; var bp:IBoundsProvider = subStyle.styleRenderer.getBoundsProvider(item, subStyle); var rect:IRectangle = bp.calculateBounds(scratch, ctx); xMin = Math.min(xMin, rect.x); xMax = Math.max(xMax, rect.x + rect.width); yMin = Math.min(yMin, rect.y); yMax = Math.max(yMax, rect.y + rect.height); } } if (xMin > xMax) { xMin = 0; xMax = 0; yMin = 0; yMax = 0; } return new YRectangle(xMin, yMin, xMax - xMin, yMax - yMin); } /** * @inheritDoc */ override public function isHit( x:Number, y:Number, ctx:ICanvasContext ):Boolean { var isHit:Boolean; var comNS:CompositeNodeStyle = this.style as CompositeNodeStyle; if (comNS != null) { var styleIt:Iterator = comNS.styles.iterator(); while (styleIt.hasNext()) { var subStyle:INodeStyle = styleIt.next() as INodeStyle; var hitTestable:IHitTestable = subStyle.styleRenderer.getHitTestable(item, subStyle); var subStyleHit:Boolean = hitTestable.isHit(x, y, ctx); isHit = isHit || subStyleHit; } } return isHit; } /** * @inheritDoc */ override public function isInBox(box:IRectangle, ctx:ICanvasContext):Boolean { return GeomSupport.rectangleIntersects( box, calculateBounds(new YRectangle(), ctx) ); } /** * @inheritDoc */ override public function lookup(type:Class):Object { var result:Object = super.lookup(type); if (result != null) return result; var comNS:CompositeNodeStyle = this.style as CompositeNodeStyle; if (comNS != null) { var styleIt:Iterator = comNS.styles.iterator(); while (styleIt.hasNext()) { var subStyle:INodeStyle = styleIt.next() as INodeStyle; result = subStyle.styleRenderer.getContext(item, subStyle).lookup(type); if (result != null) return result; } } return null; } /** * @inheritDoc */ override public function getIntersection(innerX:Number, innerY:Number, outerX:Number, outerY:Number, intersectionPoint:IPointSetter):Boolean { var intersectX:Number; var intersectY:Number; var isIntersected:Boolean; var comNS:CompositeNodeStyle = this.style as CompositeNodeStyle; if (comNS != null) { var styleIt:Iterator = comNS.styles.iterator(); var pointTmp:YPoint = new YPoint(0, 0); while (styleIt.hasNext()) { var subStyle:INodeStyle = styleIt.next() as INodeStyle; var subStyleRenderer:INodeStyleRenderer = subStyle.styleRenderer as INodeStyleRenderer; var isIntersectedBySub:Boolean = subStyleRenderer.getShapeGeometry(item as INode, subStyle).getIntersection(innerX, innerY, outerX, outerY, pointTmp); if (isIntersectedBySub) { if (!isIntersected) { isIntersected = true; intersectX = pointTmp.x; intersectY = pointTmp.y; } else { // check which one is closer if ((outerX < innerX && pointTmp.x < intersectX) || (outerX > innerX && pointTmp.x > intersectX) || (outerY < innerY && pointTmp.y < intersectY) || (outerY > innerY && pointTmp.y > intersectY)) { intersectX = pointTmp.x; intersectY = pointTmp.y; } } } } } intersectionPoint.x = intersectX; intersectionPoint.y = intersectY; return isIntersected; } /** * @inheritDoc */ override public function isInside(x:Number, y:Number):Boolean { var isInside:Boolean; var comNS:CompositeNodeStyle = this.style as CompositeNodeStyle; if (comNS != null) { var styleIt:Iterator = comNS.styles.iterator(); while (styleIt.hasNext()) { var subStyle:INodeStyle = styleIt.next() as INodeStyle; var isInsideSubStyle:Boolean = (subStyle.styleRenderer as INodeStyleRenderer).getShapeGeometry(item as INode, subStyle).isInside(x, y); isInside = isInside || isInsideSubStyle; } } return isInside; } /** * @inheritDoc */ override public function getOutline():GeneralPath { // instead of calculating the exact outline we just give back a GeneralPath containing the bounding box. return super.getOutline(); } } }