<@doc hierarchy="GMLDOM"> Aspect for drawing bipolar polyshapes that hold input and output pins on two opposite sides. @Bipolar aspect assumes that the attached object contains the method getPlugs (as appears in @gml:Connectable!). (c) SAP AG 2003-2006. All rights reserved. #INCLUDE[gml:defs.inc] Aspect Bipolar for GmlDrawing; inherit Polyshape; constructor(diagram) this.pins = {}; this.lines = {}; this.qpin = null; this.supercall(); end destructor this.supercall(); for (var k in this.pins) { this.pins[k].Destructor(); } this.pins = null; this.qpin = null; SVG.removeElement(this.pinsLayer); this.pinsLayer = null; end ////////////////////////////////////////////////////////////////////////////////////// // BASE PROPERTIES <@prop name="geometry" access="RO" static="yes" type="Object">Gets the shape's geometry constraints Extends the geometry constraints structure by adding the following members Name | Description poleStart | The minimum distance to keep between a pole start and the first pin on that pole poleEnd | The minimum distance to keep between a pole end and the last pin on that pole A pole is a contiguous block of pins arranged on the same side. In a bipolar shape there are two poles, namely the input and the output poles. ////////////////////////////////////////////////////////////////////////////////////// // ASPECT PROPERTIES <@doc type="@Lines![id]" scope="private">Gets the collection of lines connected to this shape virtual readonly property lines = null; <@doc type="@Pin![]" scope="private">Gets the collection of all shape's pins virtual property pins = null; ////////////////////////////////////////////////////////////////////////////////////// // MUTATION METHODS <@doc scope="private"> Handles a mutation event on the base object of this shape override virtual method onObjectMutate(evt) switch (evt.type) { case 'onupdateobject': this.supercall(evt); switch (evt.name) { case '@flip': this.layoutPins(true); break; case '@strokeColor': case '@textColor': for (var k in this.pins) this.pins[k].repaint(evt.name); break; } break; case 'oninsertelement': if (!ISA(evt.child, 'core.gml:Plug')) break; var pin = $DOM.createAspect('#NS[GmlDrawing]', evt.child, this); if (pin) this.layoutPins(true); break; case 'onremoveelement': if (!ISA(evt.child, 'core.gml:Plug')) break; var id=evt.child.id; if (id in this.pins) { this.pins[id].Destructor(); this.layoutPins(true); } break; default: this.supercall(evt); break; } end <@doc scope="private"> Handles a mutation event on the base object of one of this shape's pins override virtual method onSubObjectMutate(evt) if (evt.type == 'onupdateobject' && evt.name == 'name') { var pin = this.pins[evt.object.id]; if (!pin) return; if (evt.name == 'name') { pin.name = evt.value||''; this.layoutPins(true); } } end ////////////////////////////////////////////////////////////////////////////////////// // EVENT HANDLERS override virtual method select() var R = this.supercall(); if (this.qpin) this.qpin.expose(); return R; end override virtual method unselect() this.supercall(); if (this.qpin) this.qpin.conceal(); end ////////////////////////////////////////////////////////////////////////////////////// // PAINTING METHODS <@doc scope="private"> Paints the shape override virtual method paint() this.supercall(); this.pinsLayer = SVG.createElement(this.shapeNode, 'g'); if (base.getPlugs) { var plugs=base.getPlugs(); for (var k in plugs) { $DOM.createAspect('#NS[GmlDrawing]', plugs[k], this); } } this.layoutPins(false); end <@doc scope="private"> Repositions the shape and its pins after its size, position, or orientation have changed override virtual method reposition(prop, firstTime) if (!this.supercall(prop, firstTime)) return; switch (prop) { case '@pos': var L=this.lines; for (var k in L) L[k].reroute(); break; case '@size': // fall-through case '@angle': var P=this.pins; for (var k in P) P[k].reposition(true); break; case '@flip': break; } end <@doc scope="private"> Reroutes the lines connected to this shape override virtual method reroute() var L=this.lines; for (var k in L) L[k].reroute(); end <@doc scope="private"> Updates the shape's coordinates system override virtual method updateCoordSys(ox,oy,os) if (arguments.length != 3) return; this.ox = ox; this.oy = oy; this.os = os; var L=this.lines; for (var k in L) L[k].reroute(); end <@doc scope="private"> Layouts the shape's pins according to the geometry constraints virtual method layoutPins(reroute) // sort pins by direction and name var ipins=[], opins=[]; this.qpin=null; for (var k in this.pins) { var pin=this.pins[k]; if (pin.dir == #[DIR_IN]) { ipins.push(pin); } else if (pin.dir == #[DIR_OUT]) { opins.push(pin); } else if (pin.isa('core.svg:QPin')) { this.qpin = pin; } } var ilen=ipins.length, olen=opins.length; if (ilen+olen == 0) return; if (ilen > 1) SORT(ipins, 'name'); if (olen > 1) SORT(opins, 'name'); // calculate minimum shape height var geo=base.@geometry, u=#[SVG_SNAPUNIT]; var off1=(geo.poleStart||2*u)-u/2, off2=(geo.poleEnd||2*u)-u/2; this.minHeight = Math.max(off1+off2+Math.max(ilen, olen)*u, geo.minHeight||u); var needsResize = (this.minHeight > this.h); // layout input pins var sd = (base.@flip & #[SVG_FLIPX]) ? 0x02 : 0x00; var dy = (base.@flip & #[SVG_FLIPY]) ? -u : u; var y0 = (dy<0 ? -off2 : off1) + dy/2; for (var i=0, y=y0; i