@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